Submitting transactions
Your core banking system submits a transaction to OneView and receives a decision in the same response.
Authenticate with an API service account scoped to Transaction Monitoring or All licensed modules. Create one under Administration → API Service Accounts. The API key is shown only at creation and rotation.
Before the first submission, an administrator must set the institution's base currency under Transaction Monitoring → Settings. OneView rejects ingestion until this one-time setting is complete. See Base currency settings.
POST /api/transactions
Idempotency
A transaction is identified by its transactionReference together with its direction. Direction is part of
the key because an intra-bank transfer legitimately produces the same reference twice, once per leg.
- Resubmitting the same reference and direction with an identical body returns the stored decision, with
replayed: trueand a200instead of a201. It is safe to retry. - Resubmitting the same reference and direction with a different body is rejected with
409andIDEMPOTENCY_CONFLICT. OneView will not silently overwrite audit evidence.
You do not supply a separate idempotency key.
Complete request example
Send JSON with Content-Type: application/json. Monetary values may be JSON numbers or decimal strings.
Decimal strings are recommended because they preserve exact financial precision between systems.
{
"transactionReference": "TXN-NIP-10482",
"externalReference": "CBS-77104",
"direction": "OUTBOUND",
"initiatorType": "CUSTOMER",
"paymentMethod": "NIP",
"channel": "MOBILE_APP",
"status": "POSTED",
"isInternal": false,
"isGlTransaction": false,
"isCrossBorder": false,
"amount": "150000.00",
"currency": "NGN",
"feeAmount": "50.00",
"taxAmount": "3.75",
"narration": "Consultancy retainer fee",
"executedAt": "2026-08-02T10:30:00Z",
"initiator": {
"customerUniqueId": "CUS-10482",
"accountNumber": "0123456789",
"accountName": "Sample Customer",
"riskLevel": "LOW"
},
"counterparty": {
"counterpartyType": "EXTERNAL_BANK",
"accountNumber": "9876543210",
"accountName": "Sample Recipient",
"bankCode": "999999"
},
"telemetry": {
"ipAddress": "192.0.2.24",
"deviceId": "device-demo-42",
"latitude": 6.5244,
"longitude": 3.3792,
"country": "NG",
"appVersion": "4.8.0"
}
}
Top-level fields
| Field | Required | Type and accepted values | Purpose |
|---|---|---|---|
transactionReference | Yes | String, 1 to 64 characters. Letters, numbers, ., _, :, /, and -. | Your stable transaction identifier. It forms the idempotency key with direction. |
direction | Yes | INBOUND or OUTBOUND | Direction of value movement from the institution's perspective. |
initiatorType | Yes | CUSTOMER or INTERNAL_GL | Identifies whether a customer or internal general ledger account initiated the transaction. |
paymentMethod | Yes | Fixed enum. See the table below. | Payment rail or method used to execute the transaction. |
channel | Yes | Fixed enum. See the table below. | Channel from which the transaction originated. |
status | Yes | PENDING, POSTED, or SETTLED | Your core banking lifecycle status. It is not OneView's risk decision. |
isCrossBorder | Yes | Boolean | Marks whether the movement of money crosses a national border. Currency alone does not determine this value. |
amount | Yes | Non-negative decimal, up to 14 whole digits and 4 fractional digits. | Principal transaction amount. |
currency | Yes | Three uppercase ISO 4217 letters. | Currency of amount, for example NGN, USD, or GBP. |
executedAt | Yes | ISO 8601 timestamp | Time the transaction was executed or posted. This determines its monitoring time window. |
initiator | Yes | Object | Snapshot of the originating customer or GL. See below. |
counterparty | Yes | Object | Snapshot of the receiving or opposing party. See below. |
externalReference | No | String using the reference format above. | A related identifier from another system, rail, switch, or processor. |
isInternal | No | Boolean. Defaults to false. | Marks activity where both sides are within the institution. |
isGlTransaction | No | Boolean. Defaults to false. | Marks a transaction involving general ledger accounts. |
feeAmount | No | Non-negative decimal. Defaults to 0. | Total fee charged for the transaction. |
taxAmount | No | Non-negative decimal. Defaults to 0. | Tax included in or associated with the transaction fee. |
balanceBefore | No | Signed decimal | Initiator account balance before posting. Negative values are allowed for overdraft accounts. |
balanceAfter | No | Signed decimal | Initiator account balance after posting. Negative values are allowed for overdraft accounts. |
usdExchangeRate | Conditional | Positive decimal, up to 8 fractional digits. | Required for a non-USD transaction when isCrossBorder is true or its currency differs from the configured institution base currency. Express this as units of the transaction currency per 1 USD. OneView calculates usdAmount. |
narration | No | Text, up to 512 characters. | Human-readable transaction description supplied by the originating system. |
sourceOfFunds | No | Code, up to 64 characters. | Classified source of funds, when known. |
remittancePurposeCode | No | Code, up to 32 characters. | Regulatory or internal purpose code for the payment. |
initiatedAt | No | ISO 8601 timestamp | Time the customer or internal actor initiated the transaction. |
settledAt | No | ISO 8601 timestamp | Time the transaction settled. |
telemetry | No | Object | Device, network, location, and application context. |
ledgerPostings | No | Array of up to 64 objects | Debit and credit legs for GL-aware and multi-leg monitoring. |
receivedAt is not a request field. OneView generates it from the database clock when the transaction is first
stored, then returns it in the ingestion response and transaction read models. It records when OneView received
the transaction, while the required executedAt records when the source system executed or posted it. A replay
returns the original transaction's receivedAt value.
Fixed enum values
Values outside these lists are rejected.
| Field | Allowed values |
|---|---|
direction | INBOUND, OUTBOUND |
initiatorType | CUSTOMER, INTERNAL_GL |
paymentMethod | NIP, NEFT, RTGS, SWIFT, INTERNAL_TRANSFER, CARD, CASH, CHEQUE, DIRECT_DEBIT, STANDING_ORDER |
channel | MOBILE_APP, INTERNET_BANKING, USSD, ATM, POS, BRANCH, AGENT_BANKING, API, CORE_BANKING |
status | PENDING, POSTED, SETTLED |
initiator.entityType | INDIVIDUAL, CORPORATE, SOLE_PROPRIETORSHIP |
initiator.riskLevel | LOW, MEDIUM, HIGH |
initiator.status | ACTIVE, SUSPENDED, FROZEN, CLOSED |
counterparty.counterpartyType | EXTERNAL_BANK, INTERNAL_USER, VAS, INTERNAL_GL, CARD |
ledgerPostings[].entryType | DEBIT, CREDIT |
sourceOfFunds and remittancePurposeCode do not have OneView-defined enums. Their accepted formats and length
limits are documented in the top-level field table.
Currency classification and USD conversion
OneView compares each transaction's currency with the institution base currency configured in Transaction
Monitoring settings. The server records isForeignCurrency: true when they differ. This is derived by OneView
and is not a request field.
isCrossBorder is a separate required fact supplied by the source system. A transaction can be cross-border in
the institution's base currency, or domestic in a foreign currency, so OneView does not infer one from the other.
For a transaction whose currency is USD, OneView uses a USD exchange rate of 1 and sets usdAmount equal
to amount. For another currency, provide usdExchangeRate whenever the transaction is cross-border or uses a
currency other than the configured base currency. OneView divides amount by the supplied rate and stores the
result as usdAmount.
For example, if a GBP transaction has amount: "100.00" and usdExchangeRate: "0.80", where 0.80 GBP
equals 1 USD, OneView records usdAmount: "125.0000".
Initiator object
The initiator object is always required. When initiatorType is CUSTOMER, customerUniqueId is also
required. Use a stable internal customer identifier, not an email address or display name, so velocity and
historical rules resolve the same customer consistently.
| Field | Required | Description |
|---|---|---|
customerUniqueId | For CUSTOMER | Stable customer identifier in your core banking or customer master system. |
accountNumber | No | Originating account number. |
accountName | No | Customer or account display name. |
entityType | No | Customer entity classification. Accepted values are listed in the fixed enum table. |
firstName, middleName, lastName | No | Individual customer names. |
companyName | No | Corporate or business name. |
identityType, identityNumber | No | Identity document or national identifier context. |
kycLevel, riskLevel, isPep | No | Current customer due-diligence and risk context. riskLevel uses the fixed enum above. |
nationality, country, state, city, addressLine, postalCode | No | Location and address context. |
email, phoneNumber | No | Contact identifiers used for linkage and investigation. |
sourceOfWealth, occupationOrBusiness, status | No | Customer profile and account state context. status uses the fixed enum above. |
glCode, glName | No | Originating general ledger identifier and name. |
The object may contain up to 64 fields. Values must be strings of at most 512 characters, numbers, booleans,
null, or a single bounded nested object. Arrays are not accepted inside this object.
Counterparty object
The counterparty object and its counterpartyType are required. Supported types are:
counterpartyType | Typical fields | Use for |
|---|---|---|
EXTERNAL_BANK | accountNumber, accountName, bankCode, bankName, sortCode, swiftBic, iban | A beneficiary or sender at another financial institution. |
INTERNAL_USER | customerUniqueId, accountNumber, accountName, riskLevel, isPep | Another customer within your institution. |
VAS | billerCategory, billerId, productCode, recipientIdentifier | Airtime, utility, television, and other value-added services. |
INTERNAL_GL | glCode, glName, branchCode, costCenter | An internal general ledger destination or source. |
CARD | maskedPan, bin, merchantCategoryCode, terminalId, entryMode | Card, merchant, POS, and e-commerce activity. |
The counterparty object has the same 64-field and value-size limits as initiator. Supply the identifiers your
institution needs for matching and investigation, but never send full card PAN or authentication secrets.
Telemetry object
Telemetry is optional, but it improves device, network, and geographic rule coverage.
| Field | Required | Description |
|---|---|---|
ipAddress | No | Source IP address. |
deviceId or deviceFingerprintHash | No | Stable device identifier or privacy-preserving device fingerprint. |
latitude, longitude | No | Source coordinates when collected with the appropriate legal basis. |
country | No | Uppercase ISO 3166-1 alpha-2 or alpha-3 country code, such as NG or NGA. |
isVpnOrProxy | No | Whether the source system detected VPN or proxy routing. |
appVersion | No | Client application version. |
userAgent | No | Browser or application user agent. |
sessionId | No | Source-channel session identifier, such as a USSD or web session. |
Telemetry follows the same bounded-object rules as initiator. Do not include passwords, PINs, OTPs, CVVs,
full card PANs, private keys, or API credentials.
Ledger posting objects
Use ledgerPostings for journals, VAS fee splits, tax legs, and other multi-leg accounting flows. Unknown
fields in a ledger posting are rejected.
| Field | Required | Description |
|---|---|---|
glCode | Yes | General ledger code. |
entryType | Yes | DEBIT or CREDIT. |
amount | Yes | Non-negative decimal with up to 4 fractional digits. |
currency | Yes | Three uppercase ISO 4217 letters. |
postingId | No | Stable identifier for the posting leg. |
glName | No | Human-readable ledger name. |
accountNumber | No | Related customer or settlement account. |
costCenter | No | Branch, department, or operational cost-center code. |
OneView preserves the submitted array order as the leg index. Submit debits and credits as positive amounts;
use entryType to express the accounting direction.
Fields OneView will not accept
transactionId, riskScore, riskStatus, isForeignCurrency, usdAmount, baseCurrency,
baseExchangeRate, baseCurrencyAmount, baseAmount and any decision field are rejected. Identity, derived
currency facts, and the decision are OneView outputs or installation settings; accepting them from a caller
would make the stored record internally inconsistent.
status remains yours. It is your core banking lifecycle value. OneView's decision is a separate field.
Unknown fields are rejected rather than ignored, so a typo surfaces immediately instead of being silently dropped.
A successful response
{
"status": true,
"message": "Transaction evaluated",
"data": {
"transaction": {
"id": "0f4c1e2a-...",
"transactionReference": "TXN-20260729-009218",
"direction": "OUTBOUND",
"receivedAt": "2026-07-29T11:45:02.140Z",
"replayed": false
},
"decision": {
"outcome": "FLAG",
"riskScore": 35,
"evaluatedAt": "2026-07-29T11:45:02.152Z",
"evaluationMs": 11.8,
"complete": true,
"rulesEvaluated": 42,
"rulesetSnapshot": "a3f81c...",
"gradingVersion": 3,
"triggeredRules": [
{
"ruleId": "7c9e...",
"ruleVersion": 3,
"name": "High velocity 1h",
"action": "FLAG"
}
]
}
}
}
riskScore is assigned from the institution's configured Risk score grading. It is not
submitted by the caller and it is not the sum of per-rule points.
gradingVersion identifies the exact risk score grading policy that assigned the score. Store it with the
decision if your integration retains its own audit record.
Always check complete
complete: false means the decision is partial because some rules could not run. A skippedRules array names
which, with a reason code. The decision is still returned, and it is your policy whether to trust a partial
PASS.
This is not an error case and does not change the HTTP status. A rule that fails is neither treated as firing nor as not firing, because either would be misleading: one would block traffic on a bug, the other would weaken a control silently.
rulesetSnapshot identifies the exact set of rules and thresholds that ran. Together with gradingVersion, it
correlates the decision to the complete policy in force at the time.
Errors
| HTTP | code | What to do |
|---|---|---|
| 401 | Not provided | Fix credentials. Do not retry. |
| 403 | FORBIDDEN | Fix permissions. Do not retry. |
| 403 | LICENSE_MODULE_NOT_INCLUDED | Apply your fallback and alert operations. |
| 409 | TRANSACTION_MONITORING_NOT_CONFIGURED | Ask an authorized administrator to set the institution base currency. Do not retry until configuration is complete. |
| 409 | IDEMPOTENCY_CONFLICT | Do not retry. The same reference and direction were sent with a different body. |
| 400 | VALIDATION_FAILED | Fix the payload. Do not retry. An errors array names the fields. |
| 429 | Not provided | Back off and retry. |
| 503 | UPDATE_MAINTENANCE_ACTIVE | Switch to bypass mode and retry after the update. |
| 503 | TRANSACTIONS_UNAVAILABLE | Apply your fallback and retry. |
UPDATE_MAINTENANCE_ACTIVE is the explicit signal for an update drain, so you never have to infer maintenance
from a generic 503.
Reading a decision later
GET /api/transactions/{id}
Requires Read transactions. This is how you resolve a held transaction: poll for the reference you
submitted and read releaseDecision once an analyst has recorded a review.
The detail response also carries the rule evaluations, so an integration can retrieve the same explanation the analyst sees.