Recurring Payment
Create and manage subscriptions and recurring payment
How subscription works
API Environment
Environment Name | URL |
---|---|
Sandbox | https://openapi-int.qfapi.com |
API Resources
For build and manage subscriptions, the following API resources are required:
API Resources |
---|
Customer |
Payment Token |
Product |
Subscription |
Create subscription steps
Current flow of subscription creation
- Config your notification address, you will receive notification to get token_id and track the state change of subscription.
- Create customer object and get
customer_id
- Using
customer_id
and card information to create token intent and gettoken_id
- Create product object and get
product_id
, your subscription transaction amount for each billing cycle and the interval between two billing cycles will be defined in product object. - Create subscription object using
customer_id
,product_id
andtoken_id
, your subscription start time and total billing cycles will be defined in subscription object.
Subscription state
state diagram All subscription state will be pushed to merchant's backend service once triggered
Common API response parameter
Attribute | Type | Description |
---|---|---|
respcd | String | Return code, 0000 = API call succeeded |
resperr | String | result description |
respmsg | String | information description |
data | Object | result, JSON object or list of JSON object |
Customer
Customer is an API resource for merchant to store customer's information. This object can be used in PaymentToken, Subscription APIs
Create customer object
Endpoint : /customer/v1/create
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | String | No | customer name |
phone | String | No | customer contact no. |
email | String | No | customer email address |
billing_address | String | No | customer billing address, stringify JSON object |
Response parameters in data field
Attribute | Type | Description |
---|---|---|
customer_id | String | unqiue customer ID in QF system |
name | String | customer name |
phone | String | customer contact no. |
email | String | customer email address |
billing_address | JSON | customer billing address |
Update customer object
Endpoint : /customer/v1/update
Method : POST
Request parameters:
Attribute | Type | Mandatory | Description |
---|---|---|---|
customer_id | String | Yes | unqiue customer ID in QF system |
name | String | No | customer name |
phone | String | No | customer contact no. |
email | String | No | customer email address |
billing_address | JSON | No | customer billing address |
Response parameters in data field:
Attribute | Type | Description |
---|---|---|
customer_id | String | unqiue customer ID in QF system |
name | String | customer name |
phone | String | customer contact no. |
email | String | customer email address |
billing_address | JSON | customer billing address |
Inquiry customer object
Endpoint : /customer/v1/query
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
customer_id | String | No | unqiue customer Id in QF system |
name | String | No | customer name |
phone | String | No | customer contact no. |
email | String | No | customer email address |
page | Int | No | default value = 1 |
page_size | Int | No | default value = 10, the max value is 100 |
Response parameters in data field
Array of customer objects contianing the following attributes
Attribute | Type | Description |
---|---|---|
customer_id | String | unqiue customer ID in QF system |
name | String | customer name |
phone | String | customer contact no. |
email | String | customer email address |
Delete customer object
permanently delete customer object, cannot be undo. Any subscription plan associated with the deleted customer will be cancelled.
Endpoint : /customer/v1/delete
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
customer_id | String | Yes | unique customer identifier in QF system |
Product
Products are the model for goods or services that merchants will provide to the customers. It defines transaction amount, transaction currency and billing cycles(if applicable). This object will be used in subscription API.
Create product object
create a new product
Endpoint : /product/v1/create
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
name | String | Yes | product name that displays to the customer |
type | String | No | default value=onetime, possible values: onetime, recurring |
description | String | No | product descritpion |
txamt | Int | Yes | transaction amount, e.g. $1=100. Suggest value > 200 to avoid risk control |
txcurrcd | String | Yes | transaction currency, e.g. HKD |
interval | String | No | possible values: monthly, yearly, mandatory for recurring product |
interval_count | Int | No | interval between 2 charges, maximum 1 year allowed, mandatory for recurring product |
usage_type | String | No | default value=licensed, possible values: licensed |
Response parameters in data field
Attribute | Type | Description |
---|---|---|
product_id | String | unique identifer generated in QF system |
name | String | product name that displays to the customer |
type | String | default value=onetime, possible values: onetime, recurring |
description | String | product descritpion |
txamt | Int | transaction amount, e.g. $1=100. |
txcurrcd | String | transaction currency, e.g. HKD |
interval | String | possible values: monthly, yearly |
interval_count | Int | interval between 2 charges |
usage_type | String | default value=licensed, possible values: licensed |
Update product object
update current product information
Endpoint : /product/v1/update
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
product_id | String | Yes | unique identifier generated in QF system |
name | String | No | product name that displays to the customer |
description | String | No | product descritpion |
Response parameters in data field
Attribute | Type | Description |
---|---|---|
product_id | String | unique product identifer generated in QF system |
name | String | product name that displays to the customer |
type | String | default value=onetime, possible values: onetime, recurring |
description | String | product descritpion |
txamt | Int | transaction amount, e.g. $1=100. |
txcurrcd | String | transaction currency, e.g. HKD |
interval | String | possible values: monthly, yearly |
interval_count | Int | interval between 2 charges |
usage_type | String | default value=licensed, possible values: licensed |
Inquiry product object
Endpoint : /product/v1/create
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
product_id | String | No | unique product identifier generated in QF system |
name | String | No | product name that displays to the customer |
description | String | No | product descritpion |
txcurrcd | String | No | transaction currency |
interval | String | No | possible values: monthly,yearly |
page | Int | No | page no., default value=1 |
page_size | Int | No | page size, default value=10,max value=100 |
Response parameters in data field
Array of product objects containing the following attributes:
Attribute | Type | Description |
---|---|---|
product_id | String | unique identifer generated in QF system |
name | String | product name that displays to the customer |
type | String | possible values: onetime, recurring |
description | String | product descritpion |
txamt | Int | transaction amount, e.g. $1=100. |
txcurrcd | String | transaction currency, e.g. HKD |
interval | String | possible values: monthly, yearly |
interval_count | Int | interval between 2 charges |
usage_type | String | possible values: licensed |
Delete product object
only can delete product that is not assoicated with any subscription object
Endpoint : /product/v1/delete
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
product_id | String | No | unique product identifier generated in QF system |
Subscription
QFPay automatically charges the customers on every billing cycle based on the product with the provided Payment Token until the subscription is finished or cancelled. Before create subscription, payment token, customer and product must be created.
Create subscription object
Endpoint : /subscription/v1/create
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
customer_id | String | Yes | unique customer identifier in QF system |
token_id | String | Yes | unique payment token identifier in QF system |
products | Object | Yes | list of unique product identifier in QF system and quantity |
total_billing_cycles | Int | No | the total billing cycles of the subscirption, infinity if null value |
start_time | String | No | the time subscription will start to work, the first payment will be |
parameters in products:
Attribute | Type | Mandatory | Description |
---|---|---|---|
product_id | String | Yes | unique production identifier in QF system |
quantity | Int | No | default value=1 |
example request format:
{
"products": [
{
"product_id": "prod_54c3772d******9a54b236e09ec74f",
"quantity": 1
}
],
"customer_id": "cust_aaf6aae94******982c54c9cae5ba32",
"token_id": "tk_a99892fd*********d3417d168a18bb",
"total_billing_cycles": 2,
"start_time": "2020-05-14 12:32:56"
}
Response parameters in data field
Attribute | Type | Description |
---|---|---|
customer_id | String | unique customer identifier in QF system |
token_id | String | unique payment token identifier in QF system |
products | Object | list of unique product identifier in QF system and quantity |
total_billing_cycles | Int | the total billing cycles of the subscirption, infinity cycles if null value |
start_time | String | the time subscription will start to work |
example response format:
{
"resperr": "success",
"respcd": "0000",
"respmsg": "success",
"data": {
"state": "ACTIVE",
"subscription_id": "sub_ce65d6feb8******d1b2e5fc90b1ef"
}
}
Update subscription object
update current subscription
Endpoint : /subscription/v1/update
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
subscription_id | String | Yes | unique subscription identifier in QF system |
total_billing_cycles | Int | No | the total billing cycles of the subscirption, infinity if null value |
start_time | String | No | the time that subscription will start to work, it will be the first subscription payment time |
token_id | String | No | unique payment token identifier in QF system |
products | Object | No | list of unique product identifier in QF system and quantity |
Response parameters in data field
Attribute | Type | Description |
---|---|---|
subscription_id | String | unique subscription identifier in QF system |
customer_id | String | unique customer identifier in QF system |
token_id | String | unique payment token identifier in QF system |
products | Object | list of unique product identifier in QF system and quantity |
total_billing_cycles | Int | the total billing cycles of the subscirption, infinity cycles if null value |
start_time | String | the time that subscription will start to work, it will be the first subscription payment time |
state | String | subscription state |
Inquiry subscription object
Endpoint : /subscription/v1/query
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
page | Int | No | page no.,default value=1 |
page_size | Int | No | page size, default value=10, max value=100 |
subscritpion_id | String | No | unique subscription identifier in QF system |
customer_id | String | No | unique customer identifier in QF system |
token_id | String | No | unique payment otken identifier in QF system |
state | String | No | subscription state, e.g. incompelete, active,... |
Response parameters in data field
Array of subscription object containing the following attributes:
Attribute | Type | Description |
---|---|---|
subscription_id | String | unique subscription identifier in QF system |
customer_id | String | unique customer identifier in QF system |
token_id | String | unique payment token identifier in QF system |
products | Object | list of unique product identifier in QF system and quantity |
total_billing_cycles | Int | the total billing cycles of the subscirption, infinity cycles if null value |
state | String | subscription state |
next_billing_time | String | next fund deduct time |
last_billing_time | String | previous fund deduct time |
completed_billing_iteration | Int | how many billing cycles completed |
start_time | String | the time that subscription will start to work, it will be the first subscription payment time |
Cancel subscription object
cancel customer's subscription immediately
Endpoint : /subscription/v1/cancel
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
subscription_id | String | Yes | unique ID of subscription object |
Query subscription orders
query target subscription's orders
Endpoint : /subscription/billing_order/v1/list
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
subscription_id | String | Yes | unique ID of subscription object |
page | Int | No | page no.,default value=1 |
page_size | Int | No | page size, default value=10, max value=100 |
Response parameters in data field
Array of subscription order object containing the following attributes:
Attribute | Type | Description |
---|---|---|
subscription_order_id | String | subscription order identifier, format: sub_ord_ + id value of subscription_id + 4 digit order sequence number (iteration of this subscription) e.g. sub_ord_a360f06exxxxxxx4c3a_0001 stands for the first payment order for subscription sub_a360f06exxxxxxx4c3a |
subscription_id | String | unique subscription identifier in QF system, format: sub_xxxxxxxx e.g. sub_a360f06exxxxxxx4c3a |
trigger_by | String | who triggered this order payment, QF system is auto , Manual charge is manual |
sequence_no | Int | the iteration of this order in the subscription plan, e.g. 2 |
Manaul charge a subscription transaction
Use API to charge a subscription immediately for a failed order.
Endpoint : /subscription/v1/charge
Method : POST
Request parameters
Attribute | Type | Mandatory | Description |
---|---|---|---|
subscription_id | String | Yes | unique ID of subscription object |
subscription_order_id | String | No | unique ID of subscription order object |
This API only applied for a subscription that having a failed order and in the state UNPAID
, INCOMPLETE
, or PAST_DUE
. For the case that the payment is successed, if manual charge date is before scheduled next billing date, the subscription plan will continue to work with state ACTIVE
, if the manual charge date is after next billing date, the subscription plan will be cancelled. If the payment is failed, the subscription plan will keep the original state.
Recurring payment actions
Ansynchronous notification
Notifications are available for both payment token and subscription events and states change
Upon successful payment token creation or subscription activation, QFPay API will send an asynchronous notification message to the URL that defined by the merchant
To configure notification address, please send the address as well as merchant and store information via email to technical.support@qfpay.com
Format: JSON
Payment Token
Attribute | Descritpion |
---|---|
userid | QFPay Store ID |
notify_type | notification type, payment_token |
event | token event when created, possible value: NEW, MATCH(existing token for this card), CONFLICT(card information is different from existing token for this card) |
tokenid | payment token id |
token_expiry_date | token expiry date |
cardcd | card no. |
card_scheme | card scheme, e.g. VISA |
respcd | response code, e.g. 0000 (success case) |
respmsg | response message, e.g. success |
sysdtm | event trigger system time |
customer_id | customer id if available |
token_reason | tokenization reason |
token_reference | tokenization reference in system |
example:
{
"respmsg": "",
"card_scheme": "ECMC_DEBIT",
"cardcd": "5200****1096",
"tokenid": "tk_6a699aae75094caeb066f****988daa32de",
"respcd": "0000",
"token_expiry_date": "2024-04-30 00:00:00",
"sysdtm": "2024-04-29 15:37:17",
"notify_type": "payment_token",
"event": "CONFLICT"
}
Subscription state change
Available when a subscription state is changed
Attribute | Descritpion |
---|---|
notify_type | notification type,subscription |
subscription_id | unique subscription identifier, format: sub_xxxxxxxx |
state | subscription state, e.g. COMPLETED, ACTIVE, for the full list of states please reference State |
sysdtm | system time of state change |
example:
{
"state": "COMPLETED",
"sysdtm": "2024-04-24 15:19:39",
"notify_type": "subscription",
"subscription_id": "sub_e51bb914919*****f6b0fe36d"
}
Subscription payment result
Available when a subscription order payment result is received
Attribute | Descritpion |
---|---|
notify_type | notification type, subscription_payment |
subscription_id | unique subscription identifier, format: sub_xxxxxxxx e.g. sub_a360f06exxxxxxx4c3a |
subscription_order_id | subscription order identifier, format: sub_ord_ + id value of subscription_id + 4 digit order sequence number (iteration of this subscription) e.g. sub_ord_a360f06exxxxxxx4c3a_0001 |
respcd | response code, e.g. 0000 (success case) |
respmsg | response message, e.g. success |
syssn | transcation number |
txdtm | transcation time |
txamt | transcation amount. |
txcurrcd | transcation currency |
customer_id | unique customer identifier, format:cust_xxxxxx |
product_id | unique product identifier for all products, separated by comma, e.g.: prod_xxxxxa23f30,prod_xxxxxbe342ac |
cardcd | card no. |
card_scheme | only available for 0000, card scheme, e.g. VISA |
current_iteration | current iteration of this subscription, e.g. 1 |
example:
{
"txcurrcd": "HKD",
"reason": "AUTHORISED",
"cardcd": "",
"subscription_order_id": "sub_ord_a360f06eb*****ad6aff24c3a",
"product_id": "prod_8c838c17ddb043b9***11f1a85c30",
"txdtm": "2024-04-24 15:19:37",
"txamt": "300",
"card_scheme": "VISA_DEBIT-SSL",
"syssn": "20240424180500020000015704",
"respcd": "0000",
"subscription_id": "sub_e51bb914919***31d800f6b0fe36d",
"customer_id": "cust_a9c0bcf2717f4***786a10e5f8f2",
"notify_type": "subscription_payment",
"current_iteration": "1",
}