﻿# PM Dropin Error Code Reference

::: tip  

This document is intended for integrating merchants, explaining the `code` that may be received at various call entry points / timing phases when integrating the PM Dropin payment component, along with their meanings and how to handle them. This document **does not distinguish** whether the error code is generated by the SDK frontend or returned by the server.

**Merchants only need to focus on:** at which entry point, which phase, receiving what `code`, and what it means.

:::

## 0. Overview

### 0.1 How to Read This Document

The component API has only two types of entry points:

| **Entry Point**    | **Form**                                                       | **Carries code**                                                  | **Corresponding Section** |
| ------------------ | -------------------------------------------------------------- | ----------------------------------------------------------------- | ------------------------- |
| Subscription Event | `instance.on('load' /'form-check' /'payButtonClick' / ...)`    | Only `load` carries code; others are states/notifications         | §1, §2.2, etc.          |
| Trigger Action     | `instance.emit('canMakePayment' / ...)`, returns a **Promise** | resolve = success; reject = failure, `err.code` is the error code | §2.3, §3,  §4          |

The four types of payment components are uniformly described according to the following **timing phases**:

**Initialization (`ready` → `load`) → User Interaction (Card form `form-check` / System payment button `payButtonClick`) → Payment Request (`emit('canMakePayment')`) → Merchant Order Finalization (Apple Pay requires `paySuccess` / `payFail`)**.

### 0.2 Unified Conventions

| **Convention**   | **Description**                                                                                                                                                                                                                                                     |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Success Code     | Event entry success is `SUCCESS`; `emit('canMakePayment')` success is `APPLY_SUCCESS` (both have the same meaning, appearing in different locations)                                                                                                                |
| Failure Response | Uniformly `{ code, msg, displayMsg? }`: `code` see tables in each chapter; `msg` is English machine text (or server-returned text); `displayMsg` is bilingual `{ en, ar }` **text that can be directly displayed** (currently mainly appears in the card component) |
| code Passthrough | Error codes returned during the server processing phase will be **passed through as-is** to the merchant; the SDK does not translate them; this document cannot enumerate them all, see Appendix B for general handling                                             |
| Component `type` | The `load` event returns `type`: `card` / `applepay` / `googlepay` / `userinfocollect`, which can be used to distinguish components                                                                                                                                 |

### 0.3 Complete Flow (Taking Apple Pay as an example, the most complete link)

```JavaScript
const applePay = PMdropin.create('applepay', options)

applePay.on('load', (res) => { res.code === 'SUCCESS' /* Only then mount/enable component */ })
applePay.on('payButtonClick', () => { /* User clicks system button → initiates payment */ })

// Phase 1: Pull up Apple Pay system popup → User authorization → SDK completes merchant validation and token retrieval
applePay.emit('canMakePayment', payload)
  .then(res => {
    // Phase 2: Success —— res.code === 'APPLY_SUCCESS', get res.data.paymentToken
    const paymentToken = res.data.paymentToken
    // Phase 3: Merchant calls their own order/payment interface (orderAndPay in demo)
    return postOrderAndPay({ paymentToken })        // Merchant's own backend interface
  })
  .then(orderRes => {
    if (orderRes.code === 'APPLY_SUCCESS') applePay.emit('paySuccess')  // Notify component of payment success, complete system popup
    else applePay.emit('payFail')
  })
  .catch(err => { /* err.code / err.msg see §3 */ applePay.emit('payFail') })

```

## 1. General: Component Initialization Loading instance.on('load')

After creating the component, the SDK will pull the component initialization configuration. Once completed, it will notify the result through the `load` event (the four components are isomorphic, differing only in `type`):

```JavaScript
const card = PMdropin.create('card', options)
card.on('load', (data) => {
  if (data.code === 'SUCCESS') {
    // Loading succeeded; component can be mounted and enabled
  } else {
    // Loading failed; see table below
  }
})
```

</br>

| code                            | msg (Default)                                 | Description                                                                                                                                                                                                                                                    | Scope          |
| ------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| `SUCCESS`                       | Empty                                         | **Initialization Succeeded.** The component can be used normally.                                                                                                                                                                                              | All            |
| `DROPIN_INIT_FAIL`              | `Failed to initialize '{type}' Dropin!`       | **Initialization Phase:** The component failed to complete initialization within the expected time after creation (mostly due to create configuration, secret keys, or environment parameter issues). Please check create parameters and refresh to try again. | All            |
| `DROPIN_INIT_ACTIONS_FAIL`      | `Failed to register '{type}' Dropin actions!` | **Initialization Phase:** Component internal action registration failed or timed out waiting for initialization. Recommended to refresh and retry.                                                                                                             | All            |
| `DROPIN_INIT_GOOGLEPAY_FAIL`    | `Failed to init 'googlePay' button!`          | **Initialization Phase:** Google Pay button initialization failed — usually due to Google Pay JS loading failure or device/browser unsupport (HTTPS, OS version, regional restrictions). Recommended to check HTTPS protocol and device compatibility.        | googlepay only |
| `HTTP_ERR`                      | `An error occurred with the http request!`    | **Initialization Phase:** A network-layer error occurred while fetching the initialization configuration. Check network connection and retry.                                                                                                                  | All            |
| `&lt;HTTP Status Code&gt;`      | statusText                                    | **Initialization Phase:** The server returned an error HTTP status (e.g., `403` / `500`). Code represents the numeric HTTP status.                                                                                                                             | All            |
| `&lt;Backend Business Code&gt;` | Server msg                                    | **Initialization Phase:** Initialization configuration request was rejected by the server (e.g., invalid parameters, keys, or merchant status error). Handle according to server msg, or contact technical support if needed.                                  | All            |

When creating multiple components on the same page, each component will trigger its own `load` event **independently**. Please listen to them separately.

## 2. Card Payment

### 2.1 Card Component Sequence

```JavaScript
load (Success) → User fills card details → on('form-check') real-time validation feedback
               → Click pay → emit('canMakePayment')
                   ├─ Local form validation (See 2.2)
                   ├─ Server handling (See 2.3)
                   └─ Network / Timeout (See 2.2)
```

### 2.2 Form Validation Phase (on('form-check') & local validation via canMakePayment)

<b>`form-check` Event</b>: Triggered in real time as the user types. Payload contains form validation status (**no code**), example structure:
`{ isFormValid, invalidReason, displayMsg, fieldStatus: { cardnum, expdate, cvv, name } }`.

Merchants can listen to this event to control the enable/disable state of the "Pay" button: Only allow payment invocation when `isFormValid === true`.

When <b>`emit('canMakePayment')` is intercepted by local validation</b> (invalid form results in immediate reject without reaching the server):

| code              | msg (Default)                                 | Description                                                                                                                                                                                                                                                                                                                   | Scope |
| ----------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| `FORM_INVALID`    | See description                               | **Form validation failed** upon payment submission: Card number/expiry/CVV/name missing or formatted incorrectly (`msg` provides specific reasons, e.g., `No selected card`), or no card selected in recommended card mode. displayMsg contains field-level bilingual messages. Instruct the user to correct input and retry. | card  |
| `REQUEST_TIMEOUT` | error.message or `Unknown`                    | Payment request **timed out** (default 15 seconds without response). Prompt the user to retry later.                                                                                                                                                                                                                          | card  |
| `UNKNOWN_ISSUE`   | `Failed to register '{type}' Dropin actions!` | **Unknown / Internal Error:** Request network error or unhandled SDK internal exception. Retry is recommended; contact technical support if issues persist.                                                                                                                                                                   | card  |

### 2.3 Server Handling Phase (Promise Result of emit('canMakePayment'))

After passing local form validation, the SDK submits card details to the server for processing:

```JavaScript
card.emit('canMakePayment', payload)
  .then(res  => { /* Success */ })
  .catch(err => { /* err.code / err.msg / err.displayMsg */ })
```

| code                     | msg (Default)   | Description                                                                                                                                                                                                                 | Scope |
| ------------------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| `APPLY_SUCCESS`          | Server response | **Handling Succeeded.** `res` contains data returned by the server (e.g., payment token), allowing the merchant to proceed with order creation.                                                                             | card  |
| `PARAMETER_INVALID`      | Server msg      | **Server Parameter Validation Failed:** Submitted data is invalid (incomplete card information, etc.). Correct according to msg and retry.                                                                                  | card  |
| `SAVE_CARD_INFO_ERROR`   | Server msg      | **Failed to save card info** (server write error). Try again later; contact technical support if it continues to fail.                                                                                                      | card  |
| `FORM_INVALID`           | Server msg      | **Server determined form fields are invalid** (same code name as §2.2, but occurs during server-side verification). Guide the user to re-check card details.                                                               | card  |
| `NO_SELECTED_CARD`       | Server msg      | **No card selected** (in recommended card scenarios). Please prompt user to select a card first.                                                                                                                            | card  |
| `USER_INFO_NOT_COMPLETE` | Server msg      | **Additional user info collection incomplete:** Require user to first complete mandatory info (such as recipient/ID details required in certain markets) via the `userinfocollect` component before retrying payment.       | card  |
| `REQUEST_TIMEOUT`        | Server msg      | **Server processing timeout.** Prompt the user to retry later.                                                                                                                                                              | card  |
| `UNKNOWN_ISSUE`          | Server msg      | Unknown error returned by server.                                                                                                                                                                                           | card  |
| Other Backend Codes      | Server msg      | **Custom Server Error Code:** SDK passes through unrecognized backend codes as-is, while `displayMsg` falls back to standard text `ERROR` (`Something went wrong, please try again.`). See Appendix B for general handling. | card  |

<b>About `displayMsg`</b>: Failure responses from the Card component carry a `displayMsg` (`{ en, ar }` bilingual), which can be displayed directly according to the user's language settings;

Specifically in `FORM_INVALID` scenarios, `displayMsg` is a field mapping structure that requires concatenation (e.g., `Field not valid: Card number`).

### 2.4 Other Actions (No Code)

Actions like `setDisabled` / `getFormValid` / `switchTheme` / `focus` return booleans or form state objects without error codes;

When actions such as `switchTheme` fail, their Promises reject without specific business error codes.

## 3. Apple Pay

### 3.1 Apple Pay Sequence (Pay Attention to Finalization Actions)

```JavaScript
load (Success) → User clicks system payment button → on('payButtonClick') → Merchant calls emit('canMakePayment')
  → Display Apple Pay system sheet → User authorizes
      → Inside SDK: Merchant validation (applePaySession) → Retrieve token (retrievePaymentToken)
  → resolve(res: APPLY_SUCCESS + data.paymentToken) OR reject(err)
  → Merchant uses paymentToken to call own order creation API
  → Order success: emit('paySuccess') / Order failure: emit('payFail') ← Determines final success/fail state on system sheet
```

::: tip Important:

Finalization of the Apple Pay sheet is controlled by the **merchant**. After `canMakePayment resolve`, ensure merchant-side order processing is completed before calling `paySuccess`; do not call `paySuccess` prior to successful order placement.

:::

### 3.2 Parameter Interception / Local Validation Phase

The following codes are returned **immediately** upon calling `canMakePayment` (before presenting the sheet):

| code                          | msg (Default)                 | Description                                                                                                                                                                                                                                                                                        | Scope    |
| ----------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `REPEAT_REQUEST`              | `The request is repeated`     | **Duplicate Request:** Initiated while the previous payment flow is still active (sheet open/pending callback). Please wait for the previous callback before re-invoking.                                                                                                                          | applepay |
| `AMOUNT_INVALID`              | `Amount is incorrect.`        | **Invalid Amount Format:** Passed `totalAmount` is not a valid monetary amount (must be an integer or a number with at most 2 decimal places). Correct parameter and retry.                                                                                                                        | applepay |
| `MIT_PARAMS_VALIDATION_ERROR` | Aggregated English error text | **MIT / Subscription Parameter Validation Failed:** Payment parameters containing subscription plan (`subscriptionPlan`) or `mitManagementUrl` failed validation. `msg` provides aggregated error descriptions (e.g., `subject is required`). Refer to Appendix C for corrections before retrying. | applepay |

### 3.3 User Authorization / Server Handling Phase (Within Sheet)

| code                           | msg (Default)   | Description                                                                                                                                                                                                     | Scope    |
| ------------------------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `APPLY_SUCCESS`                | Server response | **Authorization Handling Succeeded.** `res.data.paymentToken` acts as payment credential; proceed with merchant order creation flow.                                                                            | applepay |
| `APPLE_PAY_SESSION_ERROR`      | error message   | **Merchant Validation Failed:** Network error/failure when SDK exchanges with server for merchant validation (`applePaySession`), interrupting Apple Pay sheet. Prompt user to retry.                           | applepay |
| `RETRIEVE_PAYMENT_TOKEN_ERROR` | error message   | **Token Retrieval Failed:** Network error/failure when retrieving payment credential (`retrievePaymentToken`). Prompt user to retry.                                                                            | applepay |
| Other Backend Codes            | Server msg      | **Business error codes passed through as-is** during server merchant validation or token retrieval phases (e.g., insufficient balance, limit exceed, risk control blocks). See Appendix B for general handling. | applepay |

### 3.4 User Actions and Internal Errors

| code                      | msg (Default)       | Description                                                                                                                                                          | Scope    |
| ------------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `APPLE_PAY_CANCEL`        | `applepay canceled` | **User Canceled:** User clicked cancel in system sheet. Not an error; no error alert needed, simply guide user to restart payment.                                   | applepay |
| `APPLEPAY_INTERNAL_ERROR` | `error.message`     | **SDK Internal Exception:** Failed to create Apple Pay session (mostly due to unsupported environment or missing config). Verify device/environment setup and retry. | applepay |

## 4. Google Pay

### 4.1 Sequence

```JavaScript
load (Success) → User clicks Google Pay system button → on('payButtonClick') → Merchant calls emit('canMakePayment')
  → Display Google Pay system sheet → User selects card & authorizes
      → Inside SDK: Fetch token (retrievePaymentToken) → 3DS/Risk Control (apply3DS)
  → resolve(res: APPLY_SUCCESS + data.paymentToken) OR reject(err)
  → Merchant uses paymentToken to call own order creation API (no system sheet finalization required)
```

### 4.2 Parameter Interception / Local Validation Phase

| code                          | msg (Default)                 | Description                                                                                                                               | Scope     |
| ----------------------------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | --------- |
| `REPEAT_REQUEST`              | `The request is repeated`     | **Duplicate Request:** Initiated while previous payment flow is incomplete. Wait for previous callback before calling again.              | googlepay |
| `AMOUNT_INVALID`              | `Amount is incorrect.`        | **Invalid Amount Format:** `totalAmount` is not an integer or a number with up to 2 decimal places. Correct parameter and retry.          | googlepay |
| `MIT_PARAMS_VALIDATION_ERROR` | Aggregated English error text | **MIT / Subscription Parameter Validation Failed.** `msg` provides aggregated error text. See Appendix C to correct parameters and retry. | googlepay |

### 4.3 User Authorization / Server Handling Phase

| code                             | msg (Default)      | Description                                                                                                                                                              | Scope     |
| -------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- |
| `APPLY_SUCCESS`                  | Server response    | **Authorization Handling Succeeded.** `res.data.paymentToken` acts as payment credential; proceed with merchant order creation flow.                                     | googlepay |
| `CANCELED`                       | Google response    | **User Canceled:** Google Pay system sheet was closed (Google Pay native `statusCode`, passed through by SDK). Not an error; re-guide payment.                           | googlepay |
| Other Google Native `statusCode` | Google response    | Other statuses returned by Google Pay JS (e.g., parameter errors defined by Google), passed through by SDK. Refer to official Google Pay documentation.                  | googlepay |
| Other Backend Codes              | Server msg         | Business error codes passed through as-is during server token retrieval / 3DS phases. See Appendix B for general handling.                                               | googlepay |
| `no_paymentToken`                | `no paymentToken`  | **SDK Internal Fallback:** Server response lacks payment token. Should not occur under normal circumstances; if present, contact technical support with request details. | googlepay |
| Exception                        | Missing parameters | **SDK Internal Fallback:** Internal invocation missing parameters. Should not occur under normal circumstances.                                                          | googlepay |

## 5. userinfocollect (User Info Collection)

- Component loading errors are identical to §1 (`load` event, `type = 'userinfocollect'`).

- The `form-check` event payload reflects collection form state (`{ isValid, invalidFields, needCollect, formData }`) and contains no `code`. Merchants can use this to determine if required fields are completed or if the form needs display.

- This component itself has no payment-related error codes. If a merchant receives `USER_INFO_NOT_COMPLETE` during Card payment (see §2.3), it indicates required user info is missing; please guide the user to complete collection before paying.

## 6. Appendix

### Appendix A: Quick Code Index

| code                                            | Entry Point                            | Phase                 | Payment Method                     | Summary Meaning                                                    |
| ----------------------------------------------- | -------------------------------------- | --------------------- | ---------------------------------- | ------------------------------------------------------------------ |
| `SUCCESS`                                       | `on('load')`                           | Initialization        | All                                | Component loaded successfully                                      |
| `APPLY_SUCCESS`                                 | `emit('canMakePayment')` resolve       | Payment Handling      | card / applepay / googlepay        | Payment handling succeeded, `paymentToken` received to place order |
| `DROPIN_INIT_FAIL` / `DROPIN_INIT_ACTIONS_FAIL` | `on('load')`                           | Initialization        | All                                | Component initialization failed                                    |
| `DROPIN_INIT_GOOGLEPAY_FAIL`                    | `on('load')`                           | Initialization        | googlepay                          | Google Pay button init failed / environment unsupported            |
| `HTTP_ERR` / `HTTP Status Code`                 | `on('load')`                           | Initialization        | All                                | Network / server error when retrieving init config                 |
| `REQUEST_TIMEOUT`                               | `emit('canMakePayment')` reject        | Payment               | card (may also return from server) | Request timeout                                                    |
| `FORM_INVALID`                                  | `emit('canMakePayment')` reject        | Form Check            | card                               | Card form invalid (local or server validation)                     |
| `NO_SELECTED_CARD`                              | `emit('canMakePayment')` reject        | Form Check            | card                               | Recommended card not selected                                      |
| `PARAMETER_INVALID`                             | `emit('canMakePayment')` reject        | Server Handling       | card                               | Server parameter validation failed                                 |
| `SAVE_CARD_INFO_ERROR`                          | `emit('canMakePayment')` reject        | Server Handling       | card                               | Failed to save card information                                    |
| `USER_INFO_NOT_COMPLETE`                        | `emit('canMakePayment')` reject        | Server Handling       | card                               | Additional user info collection incomplete                         |
| `UNKNOWN_ISSUE`                                 | `on('load')` / `canMakePayment` reject | Various Phases        | card                               | Unknown error (local or server)                                    |
| `AMOUNT_INVALID`                                | `emit('canMakePayment')` reject        | Parameter Check       | applepay / googlepay               | Invalid amount format                                              |
| `MIT_PARAMS_VALIDATION_ERROR`                   | `emit('canMakePayment')` reject        | Parameter Check       | applepay / googlepay               | MIT / Subscription parameter check failed                          |
| `REPEAT_REQUEST`                                | `emit('canMakePayment')` reject        | Request Interception  | applepay / googlepay               | Duplicate request before previous flow finished                    |
| `APPLE_PAY_SESSION_ERROR`                       | `emit('canMakePayment')` reject        | Sheet Validation      | applepay                           | Failed to exchange merchant validation session                     |
| `RETRIEVE_PAYMENT_TOKEN_ERROR`                  | `emit('canMakePayment')` reject        | Sheet Token Retrieval | applepay                           | Failed to retrieve payment credential token                        |
| `APPLE_PAY_CANCEL` / `CANCELED`                 | `emit('canMakePayment')` reject        | User Interaction      | applepay / googlepay               | User canceled transaction (Non-error)                              |
| `APPLEPAY_INTERNAL_ERROR`                       | `emit('canMakePayment')` reject        | Internal              | applepay                           | Internal exception creating payment session                        |

### Appendix B: How to Handle Unlisted Server Error Codes?

When receiving a `code` **not listed in this document's tables**:

1. Inspect msg: It is the server-returned error message (usually in English) providing the most direct context; for Card component, check `displayMsg` (bilingual text) to present directly to users.

2. Determine the phase:

- From `on('load')` → Initialization configuration rejected (secret keys, merchant status, or parameter issues);

- From `emit('canMakePayment') reject` → Payment handling rejected by backend (common reasons: insufficient funds, card declined, risk control triggers, bank rejection, etc.).

3. Recommended actions:

- Pass through or log the received `code` + `msg` as-is (avoid changing error text arbitrarily);

- Display server text or a generic failure alert to the user. Do not automatically retry the same transaction (to avoid double charging); guide the user to initiate again;

- When contacting technical support, please provide: Merchant ID, timestamp, payment component type, received code/msg, and request trace ID (`requestId`).

### Appendix C: MIT / Subscription Parameter Validation (MIT_PARAMS_VALIDATION_ERROR) Text Interpretation

On failure, `msg` returns one or more English error segments (concatenated by `; `). Refer to the mapping below to fix input parameters passed to `canMakePayment`:

| msg Segment                                         | Meaning                                                                         | Correct Value Example                                                  |
| --------------------------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| `The mitManagementUrl is invalid`                   | `mitManagementUrl` is missing or does not start with `http(s)://`               | Must start with `http(s)://`                                           |
| `subject is required`                               | Subscription title missing                                                      | `subscriptionPlan.subject` as a string                                 |
| `totalPeriods must be greater than or equal to 1`   | Total periods &lt; 1 or not an integer                                          | `subscriptionPlan.totalPeriods &ge; 1`                                 |
| `periodUnit must be one of D, W, M, Y`              | Billing period unit invalid                                                     | `subscriptionPlan.periodRule.periodUnit &isin; D/W/M/Y`                |
| `periodCount must be greater than or equal to 1`    | Billing interval per period invalid                                             | `periodRule.periodCount &ge; 1`                                        |
| `amount must be greater than or equal to 0`         | Amount per period invalid                                                       | `periodAmount.amount &ge; 0`                                           |
| `currency must be equal to XXX`                     | Subscription currency does not match order currency                             | `periodAmount.currency` must equal order `currencyCode`                |
| `currency must be a 3-character string`             | Currency code is not a 3-character string                                       | e.g., `USD`, `SAR`                                                     |
| `firstPeriodStartDate must be in the future`        | First period start date is in the past                                          | Must be a future RFC3339 timestamp (e.g., `2026-10-01T00:00:00+08:00`) |
| `xxx must be of type xxx`                           | Field type invalid                                                              | Pass the expected data type as indicated                               |
| `xxx is required` / `Invalid subscriptionPlan: ...` | Nested object (e.g., `trialConfig`) is missing or contains invalid inner fields | Complete nested fields per prompt indications                          |
