Subscription Payment
Subscription Payment Description
Subscription payment is based on bank card (VISA/Mastercard) payment and allows merchants to charge customers on a subscription cycle. It applies to scenarios such as membership subscriptions and periodic bill payments. Subscription payment is initiated with wayCode=CARD_H5 and involves two transaction modes, CIT and MIT:
| Transaction mode | Description | Initiated by | User participation | channelExtra parameter |
|---|---|---|---|---|
| CIT (Customer Initiated Transaction) | First subscription payment. The customer completes the bank card payment on the payment page and authorizes the merchant to charge on the subscription cycle afterwards | Customer | Yes | isRebilling=0 |
| MIT (Merchant Initiated Transaction) | Subsequent subscription charges. The merchant initiates the charge based on the payment credential returned by the first subscription payment, without user participation | Merchant | No | isRebilling=1 |
An empty isRebilling means a normal payment without subscription.
Subscription payment way of payment: CARD_H5 (VISA/MC bank card H5, supporting CIT/MIT subscription payment)
Subscription Payment Flow
The diagram below shows the complete subscription payment flow, including the first subscription payment (CIT) and the subsequent subscription charges (MIT):
Flow description:
- The customer starts the first subscription in the merchant system, and the merchant system calls the unified order interface to initiate the first subscription payment (CIT)
- The payment gateway initiates the first subscription payment to the channel and returns the payment redirect URL
- The merchant system redirects the customer to the payment page, and the customer completes the bank card payment and authorizes future charges
- After the payment succeeds, the payment gateway returns the payment result and
channelUserPaymentOptionIdto the merchant system via the payment notice or the order query interface - The merchant system saves
channelUserPaymentOptionIdand thepayOrderIdof the first subscription order for subsequent subscription charges - When the subscription cycle expires, the merchant system calls the unified order interface to initiate the subsequent subscription charge (MIT), without user participation
- The payment gateway initiates the charge to the channel and returns the charge result via the payment notice or the order query interface. The merchant repeats this on each subscription cycle
Unified Order (Subscription Payment)
The merchant business system initiates subscription payment orders through the unified order interface. The payment gateway distinguishes the first subscription payment (CIT) from the subsequent subscription charge (MIT) by the subscription parameters in channelExtra.
Interface description
Request URL: /api/pay/unifiedOrder
Request method: POST
Request type: application/json or application/x-www-form-urlencoded
Request parameters
| Field name | Variable name | Required | Type | Example value | Description |
|---|---|---|---|---|---|
| Merchant No. | mchNo | Yes | String(30) | M1621873433953 | Merchant No. |
| App ID | appId | Yes | String(24) | 60cc09bce4b0f1c0b83761c9 | App ID |
| Merchant order No | mchOrderNo | Yes | String(30) | 20160427210604000490 | Order No. generated by the merchant |
| Way of payment | wayCode | Yes | String(30) | CARD_H5 | Way of payment. For subscription payment, fixed: CARD_H5 |
| Amount of payment | amount | Yes | int | 100 | Amount of payment (unit: cents) |
| Currency code | currency | Yes | String(3) | HKD | Three-digit currency code: HKD |
| Client IP | clientIp | No | String(32) | 210.73.10.148 | Client IPV4 address |
| Product title | subject | Yes | String(64) | Product title test | Product title |
| Product description | body | Yes | String(256) | Product description test | Product description |
| Notify URL | notifyUrl | No | String(256) | https://www.gnete.com.hk/notify.htm | Asynchronous callback URL for payment result. A callback will only be initiated if this value is input |
| Return URL | returnUrl | No | String(256) | https://www.gnete.com.hk/return.htm | Synchronous jump notification URL for payment result |
| Expired time | expiredTime | No | int | 3600 | Expired time of order (unit: seconds, 2 hours by default). The order will expire after (created time + expired time) |
| Channel parameter | channelExtra | No | String(256) | {"userTokenId": "user_10001"} | Extra parameter initiated by a specific channel, in json format string. For subscription payment parameters, see the channelExtra subscription parameter description below |
| Extended parameter | extParam | No | String(512) | 134586944573118714 | Merchant extended parameter. It will be returned as it is during callback |
| Request time | reqTime | Yes | long | 1622016572190 | Request interface time, 13-digit timestamp |
| Interface version | version | Yes | String(3) | 1.0 | Interface version No., fixed: 1.0 |
| Signature | sign | Yes | String(32) | C380BEC2BFD727A4B6845133519F3AD6 | Signature value. For details, see the signature algorithm |
| Signature type | signType | Yes | String(32) | MD5 | Signature type. Currently, only MD5 is supported |
Request example data (first subscription payment, CIT)
{
"amount": 100,
"extParam": "",
"mchOrderNo": "mho1624005107281",
"subject": "Monthly membership subscription",
"wayCode": "CARD_H5",
"sign": "84F606FA25A6EC4783BECC08D4FDC681",
"reqTime": "1624005107",
"body": "Monthly membership subscription",
"version": "1.0",
"channelExtra": "{\"userTokenId\":\"user_10001\",\"isRebilling\":\"0\",\"rebillExpiry\":\"20271231\",\"rebillFrequency\":\"30\"}",
"appId": "60cc09bce4b0f1c0b83761c9",
"clientIp": "192.166.1.132",
"notifyUrl": "https://www.gnete.com.hk/notify.html",
"signType": "MD5",
"currency": "HKD",
"returnUrl": "",
"mchNo": "M1623984572"
}Request example data (subsequent subscription charge, MIT)
{
"amount": 100,
"extParam": "",
"mchOrderNo": "mho1624005107282",
"subject": "Monthly membership subscription",
"wayCode": "CARD_H5",
"sign": "84F606FA25A6EC4783BECC08D4FDC681",
"reqTime": "1624005107",
"body": "Monthly membership subscription",
"version": "1.0",
"channelExtra": "{\"userTokenId\":\"user_10001\",\"isRebilling\":\"1\",\"userPaymentOptionId\":\"384902353\",\"relatedTargetOrderId\":\"P202106181104177050002\"}",
"appId": "60cc09bce4b0f1c0b83761c9",
"clientIp": "192.166.1.132",
"notifyUrl": "https://www.gnete.com.hk/notify.html",
"signType": "MD5",
"currency": "HKD",
"returnUrl": "",
"mchNo": "M1623984572"
}Return parameters
| Field name | Variable name | Required | Type | Example value | Description |
|---|---|---|---|---|---|
| Return status | code | Yes | int | 0 | 0 - processing succeeded, others - processing error. For details, see the error codes |
| Return information | msg | No | String(128) | Signature failed | Specific error cause, e.g. signature failed, parameter format check error |
| Signature information | sign | No | String(32) | CCD9083A6DAD9A2DA9F668C3D4517A84 | Signature of the data inside data. If data is empty, it will not be returned |
| Return data | data | No | String(512) | {} | Returned order data, in json format |
data format
| Field name | Variable name | Required | Type | Example value | Description |
|---|---|---|---|---|---|
| Payment order No | payOrderId | Yes | String(30) | U12021022311124442600 | Returned payment system order No. |
| Merchant order No | mchOrderNo | Yes | String(30) | 20160427210604000490 | Order No. input by the merchant |
| Order state | orderState | Yes | int | 2 | Payment order state 0 - order generated 1 - paying 2 - payment succeeded 3 - payment failed 4 - cancelled 5 - refunded 6 - order closed |
| Payment data type | payDataType | Yes | String | payUrl | Payment parameter type. For subscription payment: payUrl - redirect URL |
| Payment data | payData | No | String | http://www.gnete.com.hk/pay.html | Payment parameter used to initiate the payment. For the first subscription payment (CIT), redirect the customer to this URL to complete the payment |
| Channel error code | errCode | No | String | ACQ.PAYMENT_AUTH_CODE_INVALID | Error code returned by the upstream channel |
| Channel error description | errMsg | No | String | Business Failed | Error description returned by the upstream channel |
Return example data
{
"code": 0,
"data": {
"mchOrderNo": "mho1624005107281",
"orderState": 1,
"payDataType": "payUrl",
"payData": "http://www.gnete.com.hk/pay.html",
"payOrderId": "P202106181642329900002"
},
"msg": "SUCCESS",
"sign": "F4DA202C516D1F33A12F1E547C5004FD"
}channelExtra subscription parameter description
When wayCode=CARD_H5, channelExtra carries the subscription payment parameters:
| Field name | Variable name | Required | Type | Example value | Description |
|---|---|---|---|---|---|
| User token ID | userTokenId | No | String(64) | user_10001 | User token ID, involved in subscription payment (currently only supported by some channels) |
| Subscription payment flag | isRebilling | No | String(1) | 0 | Empty - normal payment without subscription; 0 - first subscription payment (CIT); 1 - non-first subscription payment (MIT) |
| Subscription expiry date | rebillExpiry | No | String(8) | 20271231 | Subscription expiry date, format: YYYYMMDD. Required when isRebilling=0 |
| Subscription frequency | rebillFrequency | No | String | 30 | Subscription charge frequency, in days. For example, 30 means charging once every 30 days. Required when isRebilling=0 |
| User payment option ID | userPaymentOptionId | No | String(64) | 384902353 | The channelUserPaymentOptionId returned after the first subscription payment succeeds. Required when isRebilling=1 |
| Related transaction order No | relatedTargetOrderId | No | String(30) | P202106181104177050002 | The payment order No. (payOrderId) of the related first subscription payment (CIT) order. Required when isRebilling=1 |
Subscription Payment Return Fields
After the first subscription payment (CIT) succeeds, the channel returns the user payment option ID. The payment gateway returns the following new field in the order query interface (/api/pay/query) and in the payment notice:
| Field name | Variable name | Required | Type | Example value | Description |
|---|---|---|---|---|---|
| Channel user payment option ID | channelUserPaymentOptionId | No | String(64) | 384902353 | The user payment option ID returned by the channel after the subscription payment succeeds (returned by some channels). The merchant must save it and pass it as userPaymentOptionId in subsequent subscription charges (MIT) |
Order query return example data
{
"code": 0,
"data": {
"amount": 100,
"appId": "60cc09bce4b0f1c0b83761c9",
"body": "Monthly membership subscription",
"channelOrderNo": "2021061822001423031419593035",
"channelUserPaymentOptionId": "384902353",
"createdAt": 1623985457705,
"currency": "HKD",
"extParam": "",
"ifCode": "inetpay",
"mchNo": "M1623984572",
"mchOrderNo": "mho1624005107281",
"payOrderId": "P202106181104177050002",
"state": 2,
"subject": "Monthly membership subscription",
"successTime": 1623985459000,
"wayCode": "CARD_H5"
},
"msg": "SUCCESS",
"sign": "9548145EA12D0CD8C1628BCF44E19E0D"
}CIT/MIT Usage
First subscription payment (CIT)
- Call the unified order interface with
wayCode=CARD_H5, passisRebilling=0in channelExtra, together withuserTokenId,rebillExpiryandrebillFrequency - Get the returned
payData(payment redirect URL), redirect the customer to the payment page, and the customer completes the bank card payment and authorizes future charges - After the payment succeeds, obtain
channelUserPaymentOptionIdandpayOrderIdfrom the payment notice or the order query interface, and save them properly:channelUserPaymentOptionId: passed asuserPaymentOptionIdin subsequent subscription charges (MIT)payOrderId: passed asrelatedTargetOrderIdin subsequent subscription charges (MIT)
Subsequent subscription charge (MIT)
- When the subscription cycle expires, call the unified order interface with
wayCode=CARD_H5, passisRebilling=1in channelExtra, together withuserTokenId,userPaymentOptionId(the channelUserPaymentOptionId returned by the first subscription payment) andrelatedTargetOrderId(the payOrderId of the first subscription payment order) - No user participation is required. The payment gateway charges the channel directly
- Obtain the charge result from the payment notice or the order query interface, and repeat the charge on each subscription cycle
Important Notes
- An empty
isRebillingmeans a normal payment without subscription payment isRebillingcan only be empty, 0 or 1. Any other value causes the order to fail- When
isRebilling=0,rebillExpiryandrebillFrequencyare required, andrebillExpirymust be 8 digits in YYYYMMDD format - When
isRebilling=1,userPaymentOptionIdandrelatedTargetOrderIdare required relatedTargetOrderIdis the payment order No. (payOrderId) of the first subscription payment (CIT) order that succeeded. The payment gateway associates the channel transaction order accordingly. If the order is not found, the order placement fails- Each subscription charge is an independent payment order, and the payment notice and reconciliation must be handled separately
- For refunds of the bank card charges involved in subscription payment, refer to the Refund interface documentation