SDK Error Codes
Use this reference to handle errors from KoardSDK 1.0.21, the published iOS release. The cases below are exported by its KoardSDK.xcframework and available with import KoardSDK. For recovery steps, see Troubleshooting.
Reading an SDK Error
The iOS wrapper is KoardMerchantSDKError. It conforms to KoardDescribableError and provides an errorDescription string. Switch on the enum case to decide how your app recovers. There is no public numeric code or errorCode property on this enum, and bridging it to NSError does not produce a documented Koard code.
| Error information | Where to read it | How to use it |
|---|---|---|
| Koard classification | KoardMerchantSDKError case and nested case |
Choose the recovery action |
| Description | error.errorDescription |
Explain the failure; do not parse it as a stable code |
| Associated detail | message, description, or other associated value |
Retain relevant, redacted diagnostic context |
| Underlying error, when supplied | Associated Error on the cases listed below |
Inspect its native type or NSError.domain and code for diagnostics; these belong to that underlying error domain |
A thrown error and a transaction outcome are different. A returned response can contain a declined, canceled, timed-out, or errored transaction without throwing. Follow Running Payments to inspect the transaction, partial approvals, and surcharge decisions before displaying a completed receipt.
If a payment or follow-up request may have reached the server, a timeout or unreadable response leaves the outcome uncertain. Reconcile the existing transaction before offering another payment, capture, refund, or surcharge confirmation. Do not automatically replay the operation from an error handler.
KoardMerchantSDKError Reference
| Case | Meaning | Recovery |
|---|---|---|
.network |
Transport failure, including offline connections and timeouts | Restore connectivity. Inspect the wrapped error when present and reconcile any submitted operation |
.unauthorized |
Authentication is missing or expired, or the API returned HTTP 401/403 | Authenticate again and verify access to the selected merchant/location |
.blockedAccount |
Merchant account is blocked (HTTP 423) | Contact Koard support; repeated login or payment attempts will not unblock it |
.invalidRequest |
The SDK could not construct a valid request | Check the request and SDK configuration |
.rateLimited |
API rate limit (HTTP 429) | Stop immediate retries and back off; retain the message if supplied |
.server |
API rejected the request or returned a server error | Inspect the message and request context; reconcile submitted payments before retrying |
.decodingFailure |
Response could not be decoded | Retain the operation context and contact support if persistent; do not assume the payment failed |
.unsupportedPlatform |
Feature requires a newer iOS version | Use the required OS version on a supported device |
.unknown |
Unclassified failure | Inspect the underlying error when present and retain a fallback handler |
.TTPConfigurationFailed |
Tap to Pay setup or account-linking failure | Inspect the nested configuration case below |
.TTPPaymentFailed |
Tap to Pay read or payment failure | Inspect the nested payment case below |
.missingTerminalID |
Required terminal context is missing | Check the active location's terminal configuration |
.missingLocationID |
No active location is set | Select an authorized location with setActiveLocationID(...) |
.invalidTransactionResponse |
Expected transaction data is missing or invalid | Recover the transaction outcome; do not show a successful receipt |
.failedToConfirmSurcharge |
Confirming or rejecting the surcharge failed | Inspect the associated error and retrieve the transaction before another confirmation attempt |
.invalidParameters |
A required argument is missing or invalid | Correct the argument described by the associated string |
.accountNotLinked |
This device is not linked to the merchant's Tap to Pay account | Offer explicit account linking, then prepare the reader |
.readerTokenInvalid |
Reader token was rejected, is invalid, or has expired | Check the environment and credentials, then retry reader preparation; escalate persistent failures |
Associated values preserve additional context: .network(description:underlying:) carries a String and optional Error; .unknown(underlying:) carries an optional Error; .rateLimited(message:), .server(message:), and .readerTokenInvalid(...) carry optional strings. .unsupportedPlatform(requiredVersion:) and .invalidParameters(...) carry strings, and .failedToConfirmSurcharge(...) carries an Error. The two Tap to Pay wrappers carry the nested enums listed below.
HTTP Status Mapping
The published error-handling contract maps HTTP failures into Koard cases. These HTTP statuses are not a separate numeric Koard error enum.
| HTTP status | Koard case |
|---|---|
401, 403 |
.unauthorized |
423 |
.blockedAccount |
429 |
.rateLimited(message:) |
Other non-success responses, including 400, 404, and 5xx |
.server(message:) |
Do not expect an HTTP 400 to become .invalidRequest, or a 404 to have its own enum case. The wrapper does not expose the original HTTP status as a dedicated property. A .server message may include it, but message parsing is not a supported classification mechanism.
Tap to Pay Configuration Errors
These are nested under .TTPConfigurationFailed(...) as KoardMerchantSDKError.TTPConfigurationError.
| Nested case | Meaning | Recovery |
|---|---|---|
.noReader |
No payment card reader is available | Check device support, OS, and entitlement setup |
.noReaderIdentifier(Error) |
Reader identifier could not be obtained | Inspect the associated error and verify reader setup |
.accountLinkingError(Error) |
Account linking failed or was declined | Inspect the associated error; keep a merchant-triggered linking action available |
.noPSPToken |
Reader token could not be obtained | Check authentication, active location, environment, and connectivity |
.deviceConfigurationFailed |
Reader/device configuration failed | Review setup and retry preparation after resolving the cause |
.notAuthenticated |
Reader setup requires authentication | Log in before preparing or linking the reader |
prepare() does not automatically link the account. linkAccountAsync() throws when linking fails or is declined. Follow Account linking and reader preparation instead of repeatedly presenting Apple's linking sheet.
Tap to Pay Payment Errors
These are nested under .TTPPaymentFailed(...) as KoardMerchantSDKError.TTPPaymentError.
| Nested case | Meaning | Recovery |
|---|---|---|
.noPaymentResult |
No payment result was available | Treat the outcome as unresolved until checked |
.paymentCardReaderError(Error) |
Reader returned an underlying error | Inspect the associated error for reader/session context |
.paymentCardReaderNilResult |
Reader returned no result | Do not report approval; check any existing transaction before a new attempt |
.canceled |
Customer or system canceled the Tap to Pay sheet | Return to a canceled checkout state; do not show a generic payment-failed alert |
Apple reader errors remain associated Error values where supplied. Their numeric codes and availability depend on Apple's error domain and OS version. They are not additional numeric Koard error codes.
Other Exported Error Data
The framework also exports RefundError, a KoardDescribableError with statusCode: Int, message: String, and errorDescription. If your caller receives this type, those are its diagnostic fields. It does not give every KoardMerchantSDKError a statusCode property, and the current refund API returns TransactionResponse on its success path.
ApiErrorDetail (detail, httpStatusCode) and ApiErrorItem (code, message, context) are exported Codable data models, not cases of the thrown error enum. Do not assume a caught KoardMerchantSDKError exposes those fields.
Handling Errors in Code
This reader-preparation example runs UI updates on the main actor and leaves account linking as an explicit merchant action. showMessage and offerAccountLinking are callbacks supplied by your app. For transaction handling, keep the complete Running Payments implementation as the source of truth.
import Foundation
import KoardSDK
@MainActor
func prepareReader(
showMessage: (String) -> Void,
offerAccountLinking: () -> Void
) async throws {
do {
try await KoardMerchantSDK.shared.prepare()
} catch let cancellation as CancellationError {
throw cancellation
} catch let error as KoardMerchantSDKError {
switch error {
case .accountNotLinked:
offerAccountLinking()
case .unauthorized, .TTPConfigurationFailed(.notAuthenticated):
showMessage("Sign in before preparing the reader.")
case .readerTokenInvalid:
showMessage("Check the SDK environment, then prepare the reader again.")
case .rateLimited:
showMessage("Too many requests. Wait before trying again.")
case .network(_, let underlying):
if (underlying as? URLError)?.code == .cancelled {
throw CancellationError()
}
showMessage("Check your connection before preparing the reader again.")
default:
showMessage(error.errorDescription)
}
} catch {
// Preserve an unexpected error for the caller's fallback handler.
throw error
}
}
For a payment catch block, handle .TTPPaymentFailed(.canceled) as cancellation. Keep a fallback branch for other errors and future cases, and never use a successful prepare() as proof that a payment succeeded.
Troubleshooting and Support
See Troubleshooting for setup, linking, token, and payment recovery. Include the SDK version, iOS version, operation, environment, enum case (including its nested case), redacted description, and transaction/event ID when available. Include an underlying error's domain/code only when that associated error exists. Omit credentials and card data.
Published Sources
- KoardSDK 1.0.21 public Swift interface: exported enum cases, associated values, and error data models.
- Published README and changelog: HTTP mapping, explicit linking, cancellation, and reader-token behavior.

