Record an offline terminal decision
/api/v1/terminal/transactions/offline-completeRequest body
application/json
deviceIdstringRequiredpaymentSessionIdstringRemote terminal command session. The device must echo this value so the host validates amount, currency, operation, and ownership before authorization.
terminalIdstringRequiredamountintegerRequiredbaseAmountMinorintegerSubtotal before tip. When supplied, base plus tip must equal amount.
tipAmountMinorintegerTip collected before authorization.
tipSourcestringTerminal selection source such as preset:1800, fixed:100, custom, or none.
currencyCodestringRequiredtransactionTypeenumpurchasepre_authrefundoriginalTransactionIdstringRequired for a refund.
entryModestringRequiredcompletionModestringDevice/kernel completion contract selected for this acceptance mode.
railIdstringvendorstringacceptanceModestringcardSchemestringmaskedPanstringapplicationPanstringClear EMV tag 5A used only for the synchronous authorization. Mutually exclusive with panEncrypted; never log or persist.
panEncryptedstringDevice-encrypted PAN ciphertext. Mutually exclusive with clear applicationPan and track2; never log or persist outside the approved CHD boundary.
accountDataKsnstringKSN for panEncrypted. This is not the PIN KSN.
accountDataKeySchemeenumTDES_DUKPTAES_DUKPTtrack2stringClear ephemeral Track 2. Mutually exclusive with panEncrypted; never log or persist.
emvTlvobjectcryptogramstringcidstringatcstringtvrstringiadstringunpredictableNumberstringcvmstringpinBlockstringDevice-encrypted PIN block; never log. Requires the separate PIN ksn.
ksnstringPIN-encryption KSN. This is not accountDataKsn.
pinBlockFormatstringpinKeySchemestringmetadataobjectResponse
application/json
idstringRequiredStable payment identifier. Payment IDs use the engine's UUID identifier format across every acceptance channel.
merchantIdstringRequiredOwning merchant. Required on every payment: one engine needs one tenancy root, stated rather than implied by the credential used.
acceptanceChannelenumRequiredHow the payment was accepted. `EXTERNAL_RAIL` covers sales authorized by a pre-certified terminal app on someone else's rail. kepa records them for reporting and never enters their authorization loop, so they carry no kepa authorization state.
CARD_PRESENTCARD_NOT_PRESENTEXTERNAL_RAILstatusenumRequiredWhere the payment is in its lifecycle. This reconciles two previously separate machines: card-present was terminal-outcome-shaped (`APPROVED`, `REVERSED`) and online was intent-lifecycle-shaped (`REQUIRES_CONFIRMATION`, `SUCCEEDED`). They shared exactly one member. `REQUIRES_CAPTURE` covers both an online uncaptured authorization and a terminal pre-auth awaiting completion: both are authorized, holding funds, and waiting on a second message. Use `type` to tell them apart. `FAILED` means the outcome is unknown, not that no money moved — a payment that failed in flight may still be reversed.
REQUIRES_PAYMENT_METHODREQUIRES_CONFIRMATIONREQUIRES_ACTIONPROCESSINGREQUIRES_CAPTURESUCCEEDEDDECLINEDREVERSEDCANCELEDFAILEDtypeenumRequiredWhat kind of movement this is. A completed pre-authorization stays `PRE_AUTH` — completing it moves the same payment from `REQUIRES_CAPTURE` to `SUCCEEDED` rather than creating a second record. There is no `PRE_AUTH_COMPLETE` type: completion is an operation, not a state a payment can be in.
SALEPRE_AUTHREFUNDVOIDCARD_READBALANCE_INQUIRYcaptureMethodenum`AUTOMATIC` captures on approval. `MANUAL` holds the authorization open for a later capture, and is what distinguishes a completed pre-authorization from a straight sale once both are captured.
AUTOMATICMANUALcapturedAmountMinorintegernullableWhat was actually captured, which may be less than `amountMinor` — a tip adjusted down, a partial fulfilment. Null until capture, so an authorization awaiting capture is distinguishable from one captured for zero.
authExpiresAtstring · ISO 8601nullableWhen the issuer's hold lapses. An expired authorization cannot be captured: the funds are no longer reserved.
amountMinorintegerRequiredAmount in the currency's minor unit — 2500 is NZD 25.00. Named `amountMinor`, not `amount`, because the unit is the field most likely to cause a money bug and the name should carry it.
baseAmountMinorintegerRequiredSubtotal before the tip, in minor units.
currencyCodestringRequiredISO 4217 currency code.
tipAmountMinorintegerRequiredTip in minor units, where the channel supports it.
tipSourcestringnullableHow the terminal collected the tip, such as `preset:1800`, `fixed:100`, `custom`, or `none`.
cashbackAmountMinorintegerCashback in minor units, card-present only.
customerIdstringCustomer this payment belongs to, when one is attached.
referenceIdstringCaller-assigned reference, echoed back on every read.
authorizationCodestringIssuer authorization code.
responseCodestringISO 8583 response code. `"00"` is approved.
cardSchemeenumVISAMASTERCARDAMEXDISCOVERJCBUNIONPAYEFTPOSOTHERmaskedPanstringMasked account number. Never more than the first six and last four digits; the engine drops any value revealing more.
rrnstringRetrieval reference number.
declineobjectWhy a payment did not succeed, and what to do about it. The engine already computes this taxonomy to drive its own retry and cascade decisions; this exposes it rather than adding new behaviour. It is what makes "retries are automatic" legible to an integrator.
cardPresentobjectPresent when `acceptanceChannel` is `CARD_PRESENT`.
cardNotPresentobjectPresent when `acceptanceChannel` is `CARD_NOT_PRESENT`.
settlementIdstringnullableSettlement batch this payment was funded in, once settled.
metadataobjectCaller-supplied key/value metadata. Max 20 keys, 256 characters per value.
createdAtstring · ISO 8601RequiredupdatedAtstring · ISO 8601recordTerminalOfflineCompletion