Submitting transactions
Quick start

OneView documentation

Submitting transactions

The ingest API, idempotency, decision responses, and error handling.

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: true and a 200 instead of a 201. It is safe to retry.
  • Resubmitting the same reference and direction with a different body is rejected with 409 and IDEMPOTENCY_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

FieldRequiredType and accepted valuesPurpose
transactionReferenceYesString, 1 to 64 characters. Letters, numbers, ., _, :, /, and -.Your stable transaction identifier. It forms the idempotency key with direction.
directionYesINBOUND or OUTBOUNDDirection of value movement from the institution's perspective.
initiatorTypeYesCUSTOMER or INTERNAL_GLIdentifies whether a customer or internal general ledger account initiated the transaction.
paymentMethodYesFixed enum. See the table below.Payment rail or method used to execute the transaction.
channelYesFixed enum. See the table below.Channel from which the transaction originated.
statusYesPENDING, POSTED, or SETTLEDYour core banking lifecycle status. It is not OneView's risk decision.
isCrossBorderYesBooleanMarks whether the movement of money crosses a national border. Currency alone does not determine this value.
amountYesNon-negative decimal, up to 14 whole digits and 4 fractional digits.Principal transaction amount.
currencyYesThree uppercase ISO 4217 letters.Currency of amount, for example NGN, USD, or GBP.
executedAtYesISO 8601 timestampTime the transaction was executed or posted. This determines its monitoring time window.
initiatorYesObjectSnapshot of the originating customer or GL. See below.
counterpartyYesObjectSnapshot of the receiving or opposing party. See below.
externalReferenceNoString using the reference format above.A related identifier from another system, rail, switch, or processor.
isInternalNoBoolean. Defaults to false.Marks activity where both sides are within the institution.
isGlTransactionNoBoolean. Defaults to false.Marks a transaction involving general ledger accounts.
feeAmountNoNon-negative decimal. Defaults to 0.Total fee charged for the transaction.
taxAmountNoNon-negative decimal. Defaults to 0.Tax included in or associated with the transaction fee.
balanceBeforeNoSigned decimalInitiator account balance before posting. Negative values are allowed for overdraft accounts.
balanceAfterNoSigned decimalInitiator account balance after posting. Negative values are allowed for overdraft accounts.
usdExchangeRateConditionalPositive 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.
narrationNoText, up to 512 characters.Human-readable transaction description supplied by the originating system.
sourceOfFundsNoCode, up to 64 characters.Classified source of funds, when known.
remittancePurposeCodeNoCode, up to 32 characters.Regulatory or internal purpose code for the payment.
initiatedAtNoISO 8601 timestampTime the customer or internal actor initiated the transaction.
settledAtNoISO 8601 timestampTime the transaction settled.
telemetryNoObjectDevice, network, location, and application context.
ledgerPostingsNoArray of up to 64 objectsDebit 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.

FieldAllowed values
directionINBOUND, OUTBOUND
initiatorTypeCUSTOMER, INTERNAL_GL
paymentMethodNIP, NEFT, RTGS, SWIFT, INTERNAL_TRANSFER, CARD, CASH, CHEQUE, DIRECT_DEBIT, STANDING_ORDER
channelMOBILE_APP, INTERNET_BANKING, USSD, ATM, POS, BRANCH, AGENT_BANKING, API, CORE_BANKING
statusPENDING, POSTED, SETTLED
initiator.entityTypeINDIVIDUAL, CORPORATE, SOLE_PROPRIETORSHIP
initiator.riskLevelLOW, MEDIUM, HIGH
initiator.statusACTIVE, SUSPENDED, FROZEN, CLOSED
counterparty.counterpartyTypeEXTERNAL_BANK, INTERNAL_USER, VAS, INTERNAL_GL, CARD
ledgerPostings[].entryTypeDEBIT, 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.

FieldRequiredDescription
customerUniqueIdFor CUSTOMERStable customer identifier in your core banking or customer master system.
accountNumberNoOriginating account number.
accountNameNoCustomer or account display name.
entityTypeNoCustomer entity classification. Accepted values are listed in the fixed enum table.
firstName, middleName, lastNameNoIndividual customer names.
companyNameNoCorporate or business name.
identityType, identityNumberNoIdentity document or national identifier context.
kycLevel, riskLevel, isPepNoCurrent customer due-diligence and risk context. riskLevel uses the fixed enum above.
nationality, country, state, city, addressLine, postalCodeNoLocation and address context.
email, phoneNumberNoContact identifiers used for linkage and investigation.
sourceOfWealth, occupationOrBusiness, statusNoCustomer profile and account state context. status uses the fixed enum above.
glCode, glNameNoOriginating 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:

counterpartyTypeTypical fieldsUse for
EXTERNAL_BANKaccountNumber, accountName, bankCode, bankName, sortCode, swiftBic, ibanA beneficiary or sender at another financial institution.
INTERNAL_USERcustomerUniqueId, accountNumber, accountName, riskLevel, isPepAnother customer within your institution.
VASbillerCategory, billerId, productCode, recipientIdentifierAirtime, utility, television, and other value-added services.
INTERNAL_GLglCode, glName, branchCode, costCenterAn internal general ledger destination or source.
CARDmaskedPan, bin, merchantCategoryCode, terminalId, entryModeCard, 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.

FieldRequiredDescription
ipAddressNoSource IP address.
deviceId or deviceFingerprintHashNoStable device identifier or privacy-preserving device fingerprint.
latitude, longitudeNoSource coordinates when collected with the appropriate legal basis.
countryNoUppercase ISO 3166-1 alpha-2 or alpha-3 country code, such as NG or NGA.
isVpnOrProxyNoWhether the source system detected VPN or proxy routing.
appVersionNoClient application version.
userAgentNoBrowser or application user agent.
sessionIdNoSource-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.

FieldRequiredDescription
glCodeYesGeneral ledger code.
entryTypeYesDEBIT or CREDIT.
amountYesNon-negative decimal with up to 4 fractional digits.
currencyYesThree uppercase ISO 4217 letters.
postingIdNoStable identifier for the posting leg.
glNameNoHuman-readable ledger name.
accountNumberNoRelated customer or settlement account.
costCenterNoBranch, 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

HTTPcodeWhat to do
401Not providedFix credentials. Do not retry.
403FORBIDDENFix permissions. Do not retry.
403LICENSE_MODULE_NOT_INCLUDEDApply your fallback and alert operations.
409TRANSACTION_MONITORING_NOT_CONFIGUREDAsk an authorized administrator to set the institution base currency. Do not retry until configuration is complete.
409IDEMPOTENCY_CONFLICTDo not retry. The same reference and direction were sent with a different body.
400VALIDATION_FAILEDFix the payload. Do not retry. An errors array names the fields.
429Not providedBack off and retry.
503UPDATE_MAINTENANCE_ACTIVESwitch to bypass mode and retry after the update.
503TRANSACTIONS_UNAVAILABLEApply 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.