Skip to main content
Every checkout ends in exactly one PaymentResult, delivered to the callback you registered with Checkout.Contract after the operator dismisses the outcome screen. Preparing the terminal ends in exactly one ReadyResult. Both use the same eighteen ErrorCode values.

How a checkout ends

The operator reads the outcome and taps Done before your callback fires, so a second launch never races the first. Try every path in the simulator: the Scenario section picks the outcome and the error code.

PaymentResult

PaymentResult
Authorized. The money will move.
PaymentResult
The issuer, the card or the device refused. The transaction completed correctly and the answer was no, so retrying the same card usually fails the same way.
PaymentResult
Did not complete for a technical reason. This is a fault to fix, not an answer to relay to the customer. A card exchange that broke (CARD_ERROR) or authorization data that came back unusable (AUTHORIZATION_ERROR) arrives here, not as Declined, because nobody answered no.
PaymentResult
Ended deliberately before an outcome existed, by the operator, the cardholder at the PIN pad or your app.
Every variant also carries raw, a JSON snapshot of the card reader’s response for support triage, and diagnostics, decoded card diagnostics when the reader returned any. Neither ever contains cardholder data: the SDK withholds the card number, track data, cardholder name, expiry date, service code and cryptogram before either reaches your app.

Who refused a declined payment

The code on Declined tells you where the refusal happened, and that decides whether Rinne has a record of it: A null transaction with one of the last three codes means nothing reached Rinne, so there is nothing to look up or reverse. The phone cannot tell an issuer’s refusal from Rinne refusing the transaction: both arrive as DECLINED_BY_ISSUER. The case an operator can fix is a refund tapped with a card other than the sale’s. If a merchant reports declines on every card, send the requestId to support.
Print receipt fields only from Rinne’s transaction record: transaction on PaymentResult.Approved, or the record on the Rinne API when transaction is null. transactionId is the card reader’s own identifier, not a receipt field; building an authorization code or a card number from it puts fabricated data on a customer’s receipt.

After a process death

If Android kills your process while the payment screen is up, the restored screen delivers Failed with a message telling you to reconcile against the Rinne API using your requestId. It is deliberately not Cancelled: nobody cancelled anything, and the transaction may well have been captured. Reconcile before charging the customer again, with a key that holds the transaction.list permission:
An approved transaction in the response means the sale went through; an empty list means it did not, and you can retry with the same requestId.

ReadyResult

Payments.getReady answers with Ready or Failed(code, message). Three codes are worth handling at setup, because each one names who fixes it:

ErrorCode

The code on Declined, Failed, Cancelled and ReadyResult.Failed is one of eighteen values, in a fixed order that only ever grows. The managed checkout shows the operator text in the device language and offers Try again only where retrying could work. If you build your own error screen, key it off the code and use ErrorCatalog[code] for a default message, retry hint and retriable flag.
Declined and Failed are different screens on purpose. Showing a network failure as “payment declined” tells the operator to ask for another card when the real problem is connectivity, and offers a retry guaranteed to fail the same way.

Read the SDK logs

The SDK writes its own lines to Logcat under the RinneSDK tag, in debug and release builds alike. Filter by the tag to follow a payment on a connected phone:
None of these lines carries card data, a PIN, an access token or the body of a response from Rinne. The raw they log is the same card reader snapshot your app receives, with cardholder data already withheld. When you report a payment to support, send its charge payment. line; the requestId in it ties the device to Rinne’s records.
Filter by the RinneSDK tag before you save or share a log. An unfiltered Logcat dump holds every other app’s and library’s lines too, and debug logging elsewhere on the phone can include access tokens.

Next steps

Simulator

Pick any error code and see the screen, the operator text and whether Try again appears.

Device setup

Catch NFC, location and connectivity problems before a customer is waiting.