5.8 KiB
CreditCall payment streaming
Deploy ChipDNAClientCLI, then hardlink, then Operafyne. No database or configuration migration is needed. The existing CreditCall provider selection enables the new sale route; CreditCall does not implement the generic payment provider interface.
Contracts
POST /api/payment/sale accepts the existing JSON sale request, for example
{"amount":1234,"confirmNo":"BOOKING-123","currency":"GBP"}. Amount remains in
minor units. CreditCall uses its existing SDK transaction reference generation.
For CreditCall, responses contain newline-delimited JSON:
{"type":"status","code":"PAYMENT_PRESENT_CARD"}
{"type":"result","result":{"outcome":"approved","message":"Payment approved","httpStatus":200,"status":{"code":200,"message":"Approved"},"transactionReference":"native-reference","cardType":"Visa","maskedCardNumber":"************1234","expiryDate":"1228","cardHash":"existing-hash","cardReference":"existing-card-reference"}}
outcome is approved, declined, cancelled, timeout, or error. Approval
is produced only by the shared CreditCall transaction/finalization core, including
the existing confirmation behavior. httpStatus preserves the equivalent legacy
operation status even after streaming commits HTTP 200. status preserves the
existing processor StatusRec. Failure message preserves the plain description
used by the legacy flow, including its existing interpretation quirks.
Card fields are emitted only on success. Unmasked or unexpected card-number data
is omitted; encoding is not masking. Receipts and raw SDK parameter bags are not
sent to Operafyne. The new adapter never builds a redirect URL. Dojo and PayBridge
continue using their existing {"type":"result","response":...} contract.
Hardlink calls POST /start-transaction-stream/ on ChipDNAClientCLI with
{"amount":"1234","transactionType":"Sale"}. Its NDJSON consists of allowlisted
status frames (source, value), a single result containing the required SDK
fields, or a sanitized error. Receipt XML may be a JSON string field needed by
hardlink's existing receipt handler; it is never a raw line in the stream.
Confirmation continues through the existing, separate XML endpoint.
Lifetime and compatibility
/start-transaction/,/takepayment, and/takepreauthretain their existing external contracts. Preauthorization and SQL persistence/release remain legacy.- Start and each confirmation call retain their independent 300-second timeout. Confirmation still uses two attempts, retrying transport/read errors with the existing two-second delay. The generic whole-operation timeout is not used.
- Kiosk cancellation or failed/blocked kiosk delivery does not cancel upstream reading, confirmation, or receipt handling. Progress queues may drop hints when full; final results have a separate slot and are delivered at most once.
- Only the response writer writes frames. Transaction execution never waits for progress delivery. No additional delivery timer or whole-operation deadline shortens the existing HTTP call bounds.
- Native SDK 3.17 updates use
UPDATE; card notifications useNOTIFICATION, retained asCARD_STATUSon the internal wire. Normal progress does not require a reference: it is accepted only inside the existing serial transaction's active observational window. A supplied nonempty reference must match. The window opens immediately before the SDK start call and closes immediately atTransactionFinished; finalization never waits for card removal. - Unidentified
CardRemovalRequestedandCardRemovalEnforcedupdates are omitted because they can arrive after financial completion. They require a matching explicit reference.Removedremains omitted even with a reference. - Ownership is best-effort UI observation. SDK 3.17 does not establish that every queued reference-less non-removal callback has drained before another transaction starts. Such a callback may briefly display stale progress in a later active window. This accepted limitation must never affect success, decline, cancellation, timeout outcomes, confirmation, retry, receipts, PMS posting, or business state.
- After timeout, an ambiguous start error, an asynchronous SDK error during an
active window, or reference reuse/overlap, progress remains suppressed for that
Clientlifetime. New transactions, elapsed time, callbacks and automatic reconnect do not reset the guard. Payments remain enabled. - Only the exact synchronous
ClientNotConnectedToServererror safely clears an unsuppressed window and releases its unused reference: SDK 3.17StartCommandreturns it beforeSendRequest. Validation errors, mixed errors and all other unproven errors suppress observation. Safe pre-dispatch rejection never clears an existing suppression latch. - Progress cannot approve, decline, confirm, cancel, or retry a transaction.
OnlineAuthCompletedmeans waiting;Removedand unknown events are omitted.
Automated verification
In hardlink, use go test -count=1 -skip '^Test_SendMail$' ./... to exclude the
existing test that sends real email. Focused tests cover legacy parity, malformed
XML/NDJSON, retained confirmation fields and receipts, retries, disconnects,
backpressure, field filtering, and conservative status mapping. Race checks cover
the changed handler and mapper packages. No test proves absence of orphan holds.
In ChipDNAClientCLI, build ChipDnaClient.sln and Tests/StreamingTests.csproj
with MSBuild, then run Tests/bin/Debug/ChipDNAClient.StreamingTests.exe. The
test executable links the production streaming code and needs no terminal.
In Operafyne, run go test -count=1 ./...; the service tests cover structured
CreditCall sales, unchanged preauth requests, failure/retry parity, and existing
Dojo/PayBridge response handling. Run go vet ./..., go build ./..., and
git diff --check in both Go repositories.