Skip to main content

Handle errors and unclear outcomes

All calls throw TapToPayError. Most errors mean that no payment occurred. One error, outcomeUnknown, means that the card can be charged. Handle it as described in Unclear outcome.

Handle errors in code​

do {
let result = try await TapToPay.acceptPayment(
amount: amountInCents, orderId: orderId, callbackUrl: webhookUrl)
show(result)
} catch let error as TapToPayError {
switch error {
case .outcomeUnknown(let orderId):
showPending(orderId) // Do not retry.
case .cancelled:
break // No payment occurred.
case .tokenExpired, .notPrepared, .invalidToken:
await renewTokenAndPrepare()
case .locationDenied:
showLocationSettingsHint()
case .setupIncomplete(let fix):
log(fix) // The app is not set up. Correct the app as fix tells you.
hideTapToPay()
case .passcodeRequired:
showSetPasscodeHint() // Settings > Face ID & Passcode. Then try again.
case .termsDeclined:
showTermsRequired()
case .osUpdateRequired:
showUpdateIOSHint()
case .paymentFailed(.readerSetupFailed(let reason)):
log(reason) // No payment occurred. Send reason to MONEI support.
showRetry()
case .paymentFailed(let code):
showFailure(code)
default:
showError(error)
}
} catch {
showError(error)
}

A switch without a default case needs @unknown default. See Switch statements.

Errors​

ErrorThrown byMeaningWhat to do
notSupportedAll callsThe device or the iOS version does not support Tap to Pay on iPhone.Hide Tap to Pay on iPhone.
setupIncomplete(fix:)prepare, acceptPayment, isAccountLinked, linkAccountFrom SDK 0.5.0. The app is not set up for Tap to Pay on iPhone: NSLocationWhenInUseUsageDescription, the entitlement or PRODUCT_TEAM_IDENTIFIER is missing or wrong. No payment occurred. fix tells you what to change. Do not parse it.Correct the app as fix tells you, and release it again. The app cannot repair this at run time. Hide Tap to Pay on iPhone, or show that the app is not set up.
passcodeRequiredprepare, acceptPayment, isAccountLinked, linkAccountFrom SDK 0.7.0. The iPhone has no passcode. No reader setup started. No payment occurred. prepare keeps the token.Tell the user to set a passcode in Settings > Face ID & Passcode (or Touch ID & Passcode). On an iPhone that a device management (MDM) solution manages, the administrator adds a passcode policy. The SDK checks again on each call: after the user sets a passcode, the next call works with no new prepare.
locationDeniedprepare, acceptPayment, isAccountLinked, linkAccountThe user did not allow location access. Before SDK 0.5.0, also: Info.plist has no NSLocationWhenInUseUsageDescription (from 0.5.0 this gives setupIncomplete).Tell the user to allow location access in Settings, then try again.
termsDeclinedacceptPayment, linkAccountThe user did not accept Apple's terms, or the link of the account failed.Tell the user that the terms are necessary. The next linkAccount or acceptPayment shows the terms again.
invalidArgumentacceptPaymentamount is 0 or less, or orderId is empty.Correct the value.
tokenExpiredprepare, acceptPayment, isAccountLinked, linkAccountThe token expired.Get a new token from your server. Call prepare. Then try again.
invalidTokenprepareThe SDK cannot read the token.Send only the token field. Get a new token and call prepare. Until then, the other calls throw notPrepared.
notPreparedacceptPayment, isAccountLinked, linkAccountNo valid token is stored.Call prepare first.
busyacceptPayment, isAccountLinked, linkAccountA payment, a terms check (isAccountLinked) or a link (linkAccount) is in progress.Wait until it ends. Do not start a second payment while one runs. If a terms check runs, wait for it to end, then call acceptPayment.
cancelledacceptPaymentThe user cancelled on Apple's screen. No payment occurred.Start a new payment when the customer is ready.
sdkUpgradeRequiredprepare, acceptPayment, isAccountLinked, linkAccountMONEI blocked this SDK version. All these calls fail with this error.Update to a newer SDK version and release your app.
osUpdateRequiredprepare, acceptPayment, isAccountLinked, linkAccountFrom SDK 0.4.0. Apple reports that this iOS version does not support Tap to Pay on iPhone. No payment occurred.Tell the user to update iOS to the latest version. Then try again.
outcomeUnknown(orderId:)acceptPaymentThe SDK cannot tell if the payment reached MONEI. The card can be charged.Do not retry. Wait for the signed webhook, or find the orderId in MONEI. See Unclear outcome.
paymentFailed(code:)All callsThe payment or the setup failed.See Failure codes.

Failure codes​

paymentFailed(code:) has one of these TapToPayErrorCode values:

CodeMeaningWhat to do
cardDeclinedThe card was declined during the read. No payment occurred.Ask for a different card.
readerNotReadyThe reader session was not ready or expired.Try again. The SDK prepares the reader again on the next call.
locationTimeoutThe device did not get a location in 15 seconds.Make sure that Location Services are on. Then try again.
readerSetupFailed(reason:)prepare, acceptPayment, isAccountLinked or linkAccount could not set up the reader before a payment started. No payment occurred. reason is a short text for your logs and for MONEI support, for example ENABLE_ERROR PaymentCardReaderError.notAllowed. Do not parse it.Try again. If the error continues, send reason to MONEI support.
unknownThe payment did not start. No payment occurred.Try again. If the error continues, contact MONEI.

Declined payments are not errors​

A PaymentResult with the status .declined is not an error. The card was read and the issuer declined the payment. The payment is in MONEI with its paymentId. The reason is in statusMessage. See Show the decline reason. Ask the customer for a different card, and start a new payment.

Unclear outcome​

outcomeUnknown(orderId:) means that the SDK cannot tell if the payment reached MONEI. The card can be charged.

Causes:

  • A connection or server error at any step of the payment.
  • A card read error, a PIN entry error, or a lost reader session during the payment.
  • A reply that is not a clear approval or a clear decline. This can also occur when the card is declined.
  • A cancelled task.

Some of these occur before the card is charged, but the SDK cannot tell which.

Do not retry

Do not retry the payment, and do not charge again with a new orderId. The customer can pay twice.

  1. Show a pending state with the orderId.

  2. Wait for the signed webhook for this orderId.

  3. If no webhook arrives, find the orderId in MONEI:

    • In the MONEI Dashboard, open Payments and filter by order ID.

    • With the GraphQL API, use the charges query with filter.orderId:

      query {
      charges(filter: {orderId: {eq: "order-1042"}}) {
      items {
      id
      status
      amount
      }
      }
      }
  4. If no payment shows, this does not prove that the card was not charged. Contact MONEI support with the orderId before you charge the customer again.

Common questions​

Can I try again after cancelled?​

Yes. cancelled means that the user cancelled on Apple's screen and no payment occurred. Start a new payment when the customer is ready.

Why do I get notPrepared after prepare failed?​

When prepare throws invalidToken or tokenExpired, the SDK does not keep a token. Get a new token from your server, send only the token field, and call prepare again.

What does sdkUpgradeRequired mean?​

MONEI blocked the SDK version in your app. All calls that need the reader fail with this error. Update to a newer SDK version and release a new version of your app. See Versions and compatibility.

Why is a card read error an unclear outcome?​

Some reader errors can occur after the SDK sent the payment to MONEI. The SDK cannot tell these errors from errors that occur before, so it throws outcomeUnknown for all of them. This prevents a second charge to the customer by mistake.