Skip to main content

Card payment, events and failures

Card payment​

You set "type": "2" on the payment, without rrn. POSfix opens the bank's payment screen over your app and the customer taps the card. After the response, the screen closes and you are back in your app. The POSfix screen does not appear.

TerminalThe bank's app
PAX with SPS (MICB, VICB)the terminal's SPS service
Sunmi with Ashburn SmartPOS (MAIB, VICB)SmartPOS
Phone with TapXphoneTapXphone

On Sunmi and TapXphone, POSfix opens the bank's app for a card payment, for card.void and card.refund, and for closing the banking day after report.z. Android allows this only while your app is on screen and bound to POSfix; the SDK sets on its own the flag that Android 14+ requires. If your app sends commands from the background, give POSfix the “Display over other apps” permission.

On PAX with SPS you need none of this. If Android refuses to open the bank's app, the payment returns CARD_PAYMENT_DECLINED.

If the sale does not complete after the card was approved, POSfix tries on its own to void the payment at the bank. This happens when another card in the same sale is declined, when the receipt does not reach SFS, or when another fiscal operation keeps the terminal busy.

MIA QR​

On Sunmi with Victoriabank SmartPOS and on TapXphone, when the bank offers MIA QR, the customer can choose it right on the bank's screen, instead of the card. You still send "type": "2". POSfix records the payment on the fiscal receipt as “other payment instrument” (ACPS 7), and in the response cardPaymentResult.isMiaQr is true.

Events​

With setEventListener you receive the stages of the commands, so you can show them on your screen. Each event has type, requestId and data. Events reach all connected apps, so you filter them by requestId.

// sent = what posfix.execute(...) returned for the current sale
posfix.setEventListener { event ->
if (event.optString("requestId") != sent.requestId) return@setEventListener
when (event.getString("type")) {
"cardPaymentStarted" -> showMessage("Present the card")
"fiscalizing" -> showMessage("Issuing the receipt…")
"printFailed" -> showMessage("The receipt did not print — check the paper")
}
}
typeWhat happened
commandStarted / commandFinishedThe command started / finished. data.success tells you how it ended.
cardPaymentStartedThe bank's screen opened and it is waiting for the card.
cardPaymentApproved / cardPaymentDeclinedThe bank's response.
fiscalizingThe receipt is on its way to SFS.
mevRetrySFS did not respond. POSfix retries: attempt, maxAttempts, secondsLeft.
fiscalizedThe receipt is issued: receiptNumber, fiscalCode.
saleFailedThe receipt was not issued at SFS. POSfix tried to void the approved card payments.
printing / printed / printFailedPrinting the receipt. It runs separately from the response; printed or printFailed usually come after it.
cancelRequestedPOSfix received the request to stop.

You don't wait for the paper to close the sale on your screen. On printFailed, after you fix the printer, you send sale.reprint with saleId: the original comes out, not a duplicate.

Stopping a sale​

posfix.cancel(sent.requestId) stops a sale while that is still possible:

  • Before the card: the sale does not start.
  • While the customer is on the bank's screen: the bank's app cannot be closed from outside, but the customer can cancel on it. If the card is approved anyway, POSfix voids the payment right away.
  • While POSfix is retrying SFS: the wait is interrupted and the sale stops.
  • After the fiscal receipt is issued: stopping has no effect. The receipt cannot be withdrawn.

A stopped sale returns SALE_CANCELLED. Only the app that sent the command can stop it.

Failures and recovery​

Your app crashes in the middle of a sale. POSfix finishes the sale anyway. When your app restarts, you send request.result with the sale's key and you get the result. See The idempotency key.

POSfix stops in the middle of a sale. The SDK immediately ends the commands in progress with POSFIX_DISCONNECTED and calls onDisconnected. When POSfix starts again, including after an update, the SDK binds again on its own and calls onConnected. Then you check with request.result.

The terminal restarts. POSfix starts on its own after boot, without a screen.

The first command after a cold start takes a few seconds. POSfix starts its services, and your requests wait in a queue; they are not lost. If POSfix does not start within 45 s, you get ENGINE_NOT_READY.

The fiscal day​

The fiscal day lasts 24 hours from the first receipt. After it expires, sales return FISCAL_DAY_EXPIRED until you send report.z. If the terminal has the automatic Z report turned on, POSfix issues it on its own at the set time, even with its screen closed. On Sunmi, the banking day closing that follows opens SmartPOS, so it needs the “Display over other apps” permission.