# Data validation

Learn about built-in validation and implement additional scenarios for Paze on Android.

## Overview

The Paze component validates configuration, identity data, and transaction parameters before and during the payment flow. Validation runs at multiple stages:

1. **Presentment:** Session `clientId`, currency, client presentation settings, and optional identity fields when the component `Content()` is composed.
2. **Checkout:** Identity re-validation, amount check, optional `sessionId` length, and create-session request building.
3. **Complete:** `merchantCategoryCode` and complete-request fields when the SDK calls Paze complete.
4. **Merchant callbacks:** Optional approval gates via `onCheckoutComplete`, `onPreDecryption`, and `onPreAuthorisation`.


If validation fails, the SDK surfaces a `BaseSdkException` with a structured error code in the `SDK12XX` range. Most validation, checkout, and decrypt failures route to `onError`. Authorisation submission failures route to `onSubmitError`.

Missing `clientId` is detected at presentment as `SDK1202`.

## Built-in validation

The SDK validates session configuration, presentation settings, and optional identity fields before checkout proceeds. By default, the Paze component checks that:

* `allowedFundingTypes.wallets.paze.clientId` is present in the session.
* `merchantCategoryCode` is present in the session when the SDK builds the complete request.
* The transaction currency is `USD`.
* When set, `clientName` is 50 characters or fewer.
* When set, `siteName` (brand name) is 50 characters or fewer.
* When set, `paymentDescription` (statement descriptor) is 25 characters or fewer at presentment.
* Email addresses are valid RFC 5322-style format and 128 characters or fewer when provided (at presentment and again at checkout).
* Phone numbers match `1` followed by 10 digits when provided (at presentment and again at checkout).
* The transaction amount is greater than 0 at checkout.
* `sessionId` is 255 characters or fewer when set on the component config.


### Presentment and forwarded fields

The button uses static presentment: it appears after presentment validation succeeds when `Content()` is composed. Optional `emailAddress` and `phoneNumber` are validated when provided and forwarded to the Paze create-session request. Both fields are optional but recommended when you have verified shopper identity.

`acceptedPaymentCardNetworks`, `cobrand`, and `acceptedShippingCountries` are forwarded to create-session when set. For card networks, omitting the property, passing an empty list, or selecting all three supported networks (`VISA`, `MASTERCARD`, `DISCOVER`) sends no network filter to Paze.

Set `transactionData.entryType` to `EntryType.Ecom` when initialising the SDK. Paze expects an e-commerce entry type on the authorisation request. The standalone Paze button component does not validate `entryType` at presentment — it is included on the transaction request after decryption. Checkout drop-in validates `EntryType.Ecom` separately (`SDK1124`).

### Checkout identity

Component identity (`emailAddress` / `phoneNumber`) is passed to Paze during session creation when provided. Each field is validated independently when set. Identity is separate from `onGetShopper`, which supplies shopper data for Unity authorisation after decryption.

When you set one or both identity fields, the SDK sends them to Paze as follows:

| Configuration | Sent to Paze |
|  --- | --- |
| Email only | `emailAddress` |
| Phone only | `phoneNumber` |
| Email and phone | `emailAddress` and `phoneNumber` |


### Validation error codes

The Paze component returns structured error codes when built-in validation or flow checks fail:

| Error code | Description | Common causes |
|  --- | --- | --- |
| `SDK1202` | Missing `session.allowedFundingTypes.wallets.paze.clientId`. | Paze `clientId` not in session data at presentment. |
| `SDK1202A` | Missing `session.allowedFundingTypes.wallets.paze.merchantCategoryCode`. | MCC not included in session when the SDK builds the complete request. |
| `SDK1203` | `clientName` exceeds 50 characters. | `clientName` on SDK initialisation is too long when set. |
| `SDK1204` | `siteName` exceeds 50 characters. | `siteName` on SDK initialisation is too long when set. |
| `SDK1205` | `paymentDescription` exceeds 25 characters. | Statement descriptor on component config is too long when set. |
| `SDK1209` | Email address exceeds 128 characters. | `emailAddress` value is too long. |
| `SDK1210` | Email address format is invalid. | `emailAddress` is not a valid RFC 5322-style email address. |
| `SDK1211` | Phone number exceeds 15 characters. | `phoneNumber` value is too long. |
| `SDK1212` | Phone number format is invalid. | `phoneNumber` is not a US E.164 number without `+`. |
| `SDK1213` | Currency not supported. | Transaction currency is not `USD`. |
| `SDK1206` | Failed to initialize Paze SDK. | Create-session failure or missing checkout URL. |
| `SDK1200` | Failed to load Paze SDK. | Custom Tab launch failed. |
| `SDK1214` | Paze checkout failed. | Generic checkout or wallet flow failure. |
| `SDK1215` | Paze checkout did not return `checkoutResponse` for a `COMPLETE` result. | Missing checkout response. |
| `SDK1216` | Paze complete did not return `completeResponse`. | Missing complete response code. |
| `SDK1219` | Paze `completeResponse` did not contain `securedPayload`. | Secured payload missing after complete. |
| `SDK1222` | `sessionId` exceeds 255 characters. | Component `sessionId` is too long at checkout. |
| `SDK1229` | Transaction amount invalid. | Transaction amount is 0 or negative at checkout. |
| `SDK1231` | Invalid shipping country codes. | `acceptedShippingCountries` contains codes that are not valid ISO 3166-1 alpha-2 values. |
| `SDK1232` | Cobrand name required. | A `cobrand` entry has an empty `cobrandName`. |
| `SDK1233` | Failed to decrypt Paze token. | Decrypt API error or invalid secured payload. Surfaced through `onError`. |
| `SDK1235` | Paze transaction failed. | Authorisation request failed. Surfaced through `onSubmitError`, not `onError`. |


Create-session and complete API provider errors may return provider-specific codes through `PazeProviderException`, not only the `SDK12XX` values listed above. Map unknown codes using `error.message` and your backend logs. Codes such as `SDK1231` and `SDK1232` are defined in the SDK but are typically returned by the create-session API rather than thrown locally by the component.

### Validation example

Use `onError` to map SDK validation and flow errors to user-facing messages:

```kotlin
config.onError = { error ->
    when (error.errorCode) {
        "SDK1210" -> showError("Please enter a valid email address.")
        "SDK1212" -> showError("Please enter a valid US phone number (e.g. 15551234567).")
        "SDK1213" -> showError("Paze is only available for USD transactions.")
        "SDK1202", "SDK1202A" -> showError("Paze is not configured for this session.")
        "SDK1231" -> showError("Invalid shipping country configuration.")
        "SDK1232" -> showError("Cobrand configuration is incomplete.")
        "SDK1233" -> showError("Payment token could not be processed. Please try again.")
        "SDK1200", "SDK1214" -> showError("Paze checkout failed. Please try again.")
        else -> showError(error.message ?: "Payment could not be completed.")
    }
}
```

## Merchant validation gates

Beyond built-in SDK checks, you can add merchant-side approval gates at key points in the flow.

### Pre-checkout validation

Validate cart state, terms acceptance, and inventory before checkout by disabling the Paze button in your UI until pre-requisites are met. `onPazeButtonClicked` has no return value and can't cancel the flow; the SDK opens the Custom Tab as soon as the callback completes. Use `onPazeButtonClicked` only for non-blocking side effects such as analytics or clearing error messages.

To hard-block checkout after the shopper returns from Paze, return `false` from `onCheckoutComplete`.

### Post-checkout merchant validation

Use `onCheckoutComplete` to inspect checkout data and approve or reject before the SDK calls complete. Return `false` to treat the checkout as incomplete.

The following example approves checkout only after server-side validation succeeds:

```kotlin
config.onCheckoutComplete = { result ->
    val decoded = result.checkoutDecodedResponse ?: return@onCheckoutComplete false
    return@onCheckoutComplete validateCheckoutOnBackend(
        sessionId = decoded.sessionId,
        cardLastFour = decoded.maskedCard.panLastFour,
    )
}

config.onCheckoutIncomplete = { _ ->
    showMessage("Payment was not completed. Please try again.")
}
```

### Pre-decryption validation

Use `onPreDecryption` to control whether the SDK decrypts the secured payload. Return `false` to handle decryption on your backend. When omitted, the SDK defaults to decrypting.

Return `false` from `onPreDecryption` and send the secured payload to your backend in `onComplete`:

```kotlin
config.onPreDecryption = { false }

config.onComplete = { result ->
    val securedPayload = result.completeDecodedResponse?.securedPayload ?: return@onComplete
    sendToBackendForDecryption(securedPayload)
}
```

### Pre-authorisation validation

Use `onPreAuthorisation` to provide risk screening data or abort the transaction before submission. When you return `TransactionInitData(...)` with `riskScreeningData`, the SDK validates the Kount payload before submitting the transaction. Invalid risk screening data throws a `ValidationException` surfaced through `onSubmitError`.

The following example cancels authorisation when a fraud check fails, or passes Kount risk screening data when it passes:

```kotlin
config.onPreAuthorisation = {
    if (fraudCheckFailed()) {
        PazePreAuthorisationResult.Cancel
    } else {
        PazePreAuthorisationResult.TransactionInitData(
            PazeTransactionInitData(
                riskScreeningData = RiskScreeningData(
                    performRiskScreening = true,
                    userIp = getUserIpAddress(),
                ),
            ),
        )
    }
}
```

## Identity validation rules

The SDK applies the following rules to optional `emailAddress` and `phoneNumber` fields on the component config.

### Email address

Email validation runs at presentment and again at checkout when the field is set:

| Rule | Requirement |
|  --- | --- |
| Format | Valid RFC 5322-style email address (format check uses trimmed value) |
| Maximum length | 128 characters (checked before trimming) |
| Timing | Optional; validated at presentment and again at checkout when provided |


### Phone number

Phone validation runs at presentment and again at checkout when the field is set:

| Rule | Requirement |
|  --- | --- |
| Format | US number without `+` prefix: `1` followed by exactly 10 digits (`^1\d{10}$`) |
| Valid length | Exactly 11 characters (e.g., `15551234567`) |
| Maximum length | 15 characters. Values longer than 15 throw `SDK1211` before format validation |
| Timing | Optional; validated at presentment and again at checkout when provided |


Phone numbers must not include the `+` prefix or formatting characters. Use `15551234567`, not `+1 (555) 123-4567`.