Drop in - GooglePay
1. API Introduction
1.1 API List
| Sequence of Interaction | Direction | API Type | API PATH |
| 2.1 Obtain Initialization Info for Frontend Component | Merchant -> PayerMax | Backend API | /applyDropinSession |
| 2.3 Create Payment, Call Frontend Component Order API | Merchant -> PayerMax | Backend API | /orderAndPay |
| 2.4.1 Asynchronous Payment Result Notification | PayerMax -> Merchant | Backend API | /collectResultNotifyUrl |
| 2.4.2 Query Payment Transaction | Merchant -> PayerMax | Backend API | /orderQuery |
1.2 Environment Information
Sandbox Environment:
https://pay-gate-uat.payermax.com/aggregate-pay/api/gateway/<API PATH>Production Environment:
https://pay-gate.payermax.com/aggregate-pay/api/gateway/<API PATH>
1.3 Request Headers
"headers": {
"Accept": "application/json",
"sign": "Please refer to the signing rules: https://docs-v2.payermax.com/doc-center/developer/config-settings.html",//Required
"Content-Type": "application/json"
}2. Start Integration
2.1 Obtain Initialization Info for Frontend Component
The merchant server initiates an HTTP POST request through the /applyDropinSession API to obtain the client token clientKey and session token sessionKey required for frontend component initialization.
- Request Example for /applyDropinSession API:
{
"requestTime": "2024-11-20T01:56:36.753-02:00",
"keyVersion": "1",
"data": {
"country":"US",
"currency": "USD",
"totalAmount": "19.99",
"componentList": ["CARD","GOOGLEPAY"],
"userId": "1447410849000200"
},
"appId": "381ded7c863c439a9e29b4519867965a",
"version": "1.1",
"merchantNo": ""
}- Request Response Example for /applyDropinSession API:
{
"msg": "",
"code": "APPLY_SUCCESS",
"data": {
"sessionKey": "964bffa7c9eb4951bd5ba11a2691e5ed",
"notSupportedComponent": [],
"clientKey": "8eef820ecbd443b7a608c2e0863750eb"
}
}2.2 Render Frontend Component
- Include the CDN package in the relevant HTML page.
<script src="https://cdn.payermax.com/dropin/js/pmdropin.min.js"></script>- Embed a container area for the
ApplePaybutton on the merchant page using adivtag.
<div class="frame-googlepay">
<!-- Form Content -->
</div>- Initialize PayerMax Frames and mount GooglePay.
const googlePay = PMdropin.create('googlepay', {
clientKey: "8eef820ecbd443b7a608c2e0863750eb",
sessionKey: "0fdde7eda5fe4cc28ca8fdc759e28dc1",
sandbox: true,
payButtonConfig: {
buttonRadius: "12",
buttonColor: "white",
buttonType: "order",
buttonLocale: "en",
width: "240px",
height: "40px"
}
});
//Mount the button
googlePay.mount('.frame-googlepay');- Listen to the button status. Once the user completes the Google Pay authentication flow, the frontend receives the
paymentToken. The server then initiates the payment and returns theredirectUrlto the frontend to guide the user through 3DS authentication.
googlePay.on('ready', () => {
console.log('Component initialized');
})
googlePay.on('load', (res = {}) => {
const { code, msg } = res || {};
if (code === "SUCCESS") {
console.log('[merchant][load]success:', res)
} else {
console.log('[merchant][load]fail:', res)
}
})
googlePay.on('payButtonClick', (res) => {
googlePay.emit('setDisabled', true);
googlePay.emit('canMakePayment')
.then(paymentRes => {
console.log('canMakePayment')
if (paymentRes.code === 'APPLY_SUCCESS') {
const paymentToken = paymentRes?.data?.paymentToken;
console.log('paymentToken:', paymentToken)
// ⚠️ Initiate payment API
// The merchant requests their own backend API to place the order.
// The merchant constructs the request parameters using params, which must include the paymentToken
const params = { // Add params definition
token: paymentToken,
};
_postapi('orderAndPay', params)
.then(apiRes => {
const code = (apiRes || {}).code;
if (code === 'APPLY_SUCCESS') {
if(apiRes.threeDSUrl){
handle3DS(threeDSUrl)
// Complete 3DS via the PayerMax in-component popup, or open threeDSUrl in a new browser tab to complete 3DS
}
googlePay.emit('paySuccess');// Payment successful, the Google Pay component disappears
} else {
googlePay.emit('payFail');// Payment failed, the Google Pay component disappears
}
googlePay.emit('setDisabled', false);// ⚠️ Unfreeze the form after the payment API call completes
})
.catch(err => {
console.error('API request failed:', err);
googlePay.emit('setDisabled', false);// Unfreeze the form if an exception occurs
});
}
})
.catch(err => {
console.error('Payment capability check failed:', err);
googlePay.emit('setDisabled', false);
});
});
// If the returned URL (which is the 'threeDSUrl') is obtained after 'orderAndPay', use the 'handle3DS' method to invoke the popup
function handle3DS(threeDSUrl) {
googlePay.create3DSPopup({
url: threeDSUrl,
// If width/height is not passed, it will be automatically calculated based on the device and viewport; it can also be explicitly passed as '80%', '400px', etc
})
.then(res => {
if (res.code === '3DS_PROCESSED') {
// 3DS flow completed, proceed with the payment process.
console.log('3DS flow completed', res.data);
// The merchant needs to maintain the existing logic here; the merchant side should actively query the payment result to continue subsequent interactions
proceedPayment(res.data);
}
})
.catch(err => {
if (err.code === 'USER_CANCEL') {
// The merchant can choose not to handle this, but should allow the user to continue clicking the payment button
showMessage('You have closed the authentication window');
} else {
showMessage('An exception occurred during authentication, please try again');
}
});
}- Get the
paymentToken. Once the user confirms the payment on the frontend, the frontendcanMakePaymentAPI will return the following information, which is used for the backend to initiate the payment.
{
"msg": "",
"code": "APPLY_SUCCESS",
"data": {
"paymentToken": "CPT771e98494eff41f1a03a715ebab69cc9",
"cardOrg": "VISA",
"maskCardNumber": "444433****1111",
"cardExpirationMonth": "12",
"cardType": "CREDIT",
"cardExpirationYear": "26",
"cardHolderFullName": "Jemy Cheung",
"agreementAccepted": true,
"cardBinNo": "444433",
"cardIssuingCountry": "US"
}
}2.3 Create Payment
- Merchant Server: Call the /orderAndPay API to initiate an HTTP POST request and create a payment.
- /orderAndPay API request example:
{
"requestTime": "2024-11-20T01:56:45.802-02:00",
"keyVersion": "1.5",
"data": {
"currency": "USD",
"country":"US",
"totalAmount": 19.99,
"expireTime": "3600",
"paymentDetail": {
+ "paymentToken": "dbe78b7dd4fa4b668bacfdcc7153821d",//Callback to frontend paymentDetail after the user enters card info and clicks pay
"buyerInfo": {
"clientIp": "146.75.136.237",
"userAgent": "Chrome"
},
+ "sessionKey": "abf62fdcf9c4408cb73117db6e740713"
},
"frontCallbackUrl": "https://",
"subject": "xxx Game HK Limited",
"outTradeNo": "ov1_5b89ced71d764ed9994e6882d88082f7",
"notifyUrl": "https://",
"userId": "1447410849000200",
"integrate": "Direct_Payment",
"terminalType": "WEB"
},
"appId": "381ded7c863c439a9e29b4519867965a",
"version": "1.4",
"merchantNo": "P04010116880289"
}- /orderAndPay API response example:
{
"msg": "Success.",
"code": "APPLY_SUCCESS",
"data": {
"outTradeNo": "test_da78b1f3c2f9443b966347fc89305fc9",
"tradeToken": "T2024052805951921811176",
"status": "SUCCESS"
}
}2.4 Get Payment Result
The data.status in the response of the Create Payment/orderAndPay API is not the final payment status. Therefore, merchants should not use it directly to update the payment result.
2.4.1 Via Payment Notification
Please refer to Payment Result - Via Payment Notification.
2.4.2 Via Payment Inquiry
Please refer to Payment Result - Via Payment Inquiry.
3. API
Usage method: PMdropin.API.
| API | Description | Details |
|---|---|---|
| create | Instantiate a built-in component | Refer create |
| mount | Mount instantiated component to div tag | Refer mount |
| on | Listen events | Refer on |
| emit | Trigger events | Refer emit |
3.1 create
Used to initialize components, please use PMdropin.create(ComponentName, Options).
ComponentName Explanation
| ComponentName | Field Type | Description |
|---|---|---|
| applepay | string | ApplePay Compoment |
Options Explanation
| Options | Required Or Not | Field Type | Default Value |
|---|---|---|---|
| clientKey | Y | String | - |
| sessionKey | Y | String | - |
| sandbox | N | Boolean | false |
| theme | N | String | light |
| payButtonStyle | N | String | - |
3.2 mount
sed to mount initialization component instances, please use PMdropin.mount(Tag).
Tag Explanation
| Tag | Description |
|---|---|
| id | The value of the id element that needs to be mounted, such as PMdropin.mount('#applepay-frame') |
| class | The value of the class element that needs to be mounted, such as PMdropin.mount('.applepay-frame') |
3.3 on
Used to listen to component built-in response events, please use PMdropin.on(Event, CallbackFunction).
Event Explanation
| Tag | Description | Returned Value |
|---|---|---|
| ready | Triggered when the component completes loading | null |
| payButtonClick | Triggered when the ApplePay button is clicked | null |
3.4 create3DSPopup
Used to open the 3DS authentication page within an in-component popup.
Language Settings Note: The SDK automatically retrieves the language from the instance configuration; there is no need to pass it separately in create3DSPopup.
Input Parameters:
| Parameter | Type | Required | Default Value | Description |
|---|---|---|---|---|
| url | string | Y | - | The 3DS authentication page URL (obtained from the orderAndPay API). |
| showMask | boolean | N | true | Whether to display the background mask overlay. |
| width | string | N | Responsive | Popup width. If omitted, it will be automatically calculated based on the device/viewport. |
| height | string | N | Responsive | Popup height. If omitted, it will be automatically calculated based on the device/viewport. |
Returns:
| CODE | Description | Handling Suggestions |
|---|---|---|
3DS_PROCESSED | 3DS process has been handled. | Proceed with the subsequent payment flow, and actively query the final authentication result via the API. |
USER_CANCEL | User closed the popup. | Prompt the user that the window has been closed, and allow them to retry. |
INVALID_PARAMS | Invalid input parameters for the call. | Check the input parameters based on err.msg (e.g., ensure the URL is required, non-empty, and of the correct type), then retry after correction. |
3.5 emit
用于调用组件内置方法,使用方法PMdropin.emit(Event, Params)。
| Event | Params | 描述 |
|---|---|---|
| canMakePayment | Object | 获取本次支付token |
| switchTheme | string | 切换主题 |
| setDisabled | Boolean | 设置组件可用状态 |
| setpayButtonConfig | Object | 设置按钮样式 |
3.5.1 emit.canMakePayment
- Checks whether the current component status meets the conditions to initiate a payment, and returns the
paymentTokenafter verification passes.
PMdropin.emit('canMakePayment', params?)params is an optional parameter. If the merchant server has already provided complete payment information when calling the /applyDropinSession API, you can call PMdropin.emit('canMakePayment') directly without passing parameters.
- Options Configuration: | Options | Required | Field Type | Description | | :--- | :---: | :---: | :--- | | totalAmount | N | String | Payment amount, formatted as a pure numeric string (e.g., '1.00'). This is only recommended for scenarios where the merchant server did not pass the amount when calling the
/applyDropinSessionAPI to obtain pre-component initialization information. This amount is solely used for display within the Apple Pay payment sheet. |
Example:
PMdropin.emit('canMakePayment', {
totalAmount: '1.00'
})Notes:
totalAmountonly accepts valid numeric strings (e.g.,'0.01','99.99'). If an invalid value is passed, the API will return the error codeAMOUNT_INVALID.- If the merchant server has already provided the amount when calling
/applyDropinSession, the amount used during final order submission must be consistent with it; otherwise, it may lead to payment failure or risk control interception.- Please ensure that the
totalAmountpassed incanMakePaymentis strictly consistent with the amount during final order submission; otherwise, it may lead to payment failure or risk control interception.
canMakePayment Response:
| Code | Description |
|---|---|
| APPLY_SUCCESS | Successfully obtained the paymentToken. |
| UNKNOWN_ISSUE | Exception occurred / Internal error. |
| AMOUNT_INVALID | Invalid input amount format. |
3.5.2 emit.setDisabled
- Set the component available state
- Type:
Boolean - Default:
false
// Button disabled state
PMdropin.emit('setDisabled', true)
// Button enabled state
PMdropin.emit('setDisabled', false)3.5.3 emit.setpayButtonConfig
- Sets the button styles
- Type:
Object - Default:
{
buttonRadius: "12", // Sets the Google Pay button border radius. String
buttonColor: 'default', // Sets the button color. "default"/"white"/"black"
buttonType: 'plain',
buttonLocale: 'en',
width: "240px",
height: "40px",
}4. Internal Field Description
| Field | Default Value | Type | Enumeration | Description |
| width | "240px" | String | / | Set Google Pay button width |
| height | "40px" | String | / | Set Google Pay button height |
| buttonRadius | "12" | String | / | Set the border radius of the googlepay button String |
| buttonColor | 'default' | String | 'default'/'white'/ 'black' | Set button color |
| buttonType | 'plain' | String | "plain","buy","book","checkout","donate","order","pay","subscribe" | Set button type Same as GooglePay official. See Preview demo for customized button |
| buttonLocale | 'en' | String | 'en'/'ja'/'zh'/... International language encoding | Set the multi-language text on the button, the same as GooglePay official, only supports the specified type, such as "checkout", "donate", etc. |
5. Color Display
| Input | Effect Preview |
| default | ![]() |
| white | ![]() |
| black | ![]() |
| 入参 | 效果预览 |
| default | ![]() |
| white | ![]() |
| black | ![]() |
6. buttonType Display
| Input | Effect Preview |
| "plain" | ![]() |
| "buy" | ![]() |
| "book" | ![]() |
| "checkout" | ![]() |
| "donate" | ![]() |
| "order" | ![]() |
| "pay" | ![]() |
| "subscribe" | ![]() |
7. buttonLocale Display
| Input | Effect Preview | Description |
| "ja" | ![]() ![]() | Japanese |
| "bg" | ![]() ![]() | Bulgarian |















