# API Virtual account
# Support Method
Method | Require User Info |
---|---|
SPEI | Required |
Luxpag provide virtual SPEI account: Merchants can apply for virtual SPEI account from Luxpag. Luxpag response with information of a virtual SPEI acount. Merchants forward this virtual SPEI account to one user. The user pay to this virtual account. The channel received the fund and callback to Luxpag. Luxpag generate an order and callback to the merchant to inform the SUCCESS payment.
# Request Base URL
Test Environment : https://gateway-sandbox.luxpag.com
Prod Environment : https://gateway.luxpag.com
# EndPoints
Create virtual account: /virtual-account/spei/create
Cancel virtual account: /virtual-account/spei/cancel
Query virtual account: /virtual-account/spei/query
Number of available accounts: /virtual-account/spei/quantity
# Request Header
Parameter | Required | Description |
---|---|---|
Content-Type | recommend | application/json |
Authorization | yes | Basic Base64(app_id:secret_key) |
# Request Body (JSON format)
# Create virtual account
Parameter | Type | Required | Max Length(or Default Value) | Description |
---|---|---|---|---|
app_id | string | yes | 32 | created app's id at dashboard |
timestamp | string | yes | 19 | yyyy-MM-dd HH:mm:ss |
notify_url | string | yes | 255 | IPN URL to merchant |
customer.buyer_id | string | yes | 128 | merchant user's id |
customer.email | string | yes | user's email('+' is not supported) | |
customer.name | string | no | user's name | |
customer.phone | string | no | user's mobile phone number | |
customer.identify.number | string | yes | user's ID number | |
customer.identify.type | string | yes | user's ID type |
# Query virtual account
Parameter | Type | Required | Max Length(or Default Value) | Description |
---|---|---|---|---|
app_id | string | yes | 32 | created app's id at dashboard |
timestamp | string | yes | 19 | yyyy-MM-dd HH:mm:ss |
account_id | string | yes | Virtual Account ID |
# Cancel virtual account
Parameter | Type | Required | Max Length(or Default Value) | Description |
---|---|---|---|---|
app_id | string | yes | 32 | created app's id at dashboard |
timestamp | string | yes | 19 | yyyy-MM-dd HH:mm:ss |
account_id | string | yes | Virtual Account ID |
# Number of available accounts
Parameter | Type | Required | Max Length(or Default Value) | Description |
---|---|---|---|---|
app_id | string | yes | 32 | created app's id at dashboard |
timestamp | string | yes | 19 | yyyy-MM-dd HH:mm:ss |
# Request Sample
curl --location --request POST 'https://gateway.luxpag.com/virtual-account/spei/create' \
--header 'Authorization: Basic Base64(appid:secret_key)' \
--header 'Content-Type: application/json' \
--data-raw '{
"app_id": "app_id",
"notify_url": "notify_url",
"timestamp": "{{datetime}}",
"customer": {
"email": "email",
"buyer_id": "buyer_id"
}
}'
curl --location --request POST 'https://gateway.luxpag.com/virtual-account/spei/query' \
--header 'Authorization: Basic Base64(appid:secret_key)' \
--header 'Content-Type: application/json' \
--data-raw '{
"app_id": "app_id",
"account_id": "account_id",
"timestamp": "{{datetime}}"
}'
curl --location --request POST 'https://gateway.luxpag.com/virtual-account/spei/cancel' \
--header 'Authorization: Basic Base64(appid:secret_key)' \
--header 'Content-Type: application/json' \
--data-raw '{
"app_id": "app_id",
"account_id": "account_id",
"timestamp": "{{datetime}}"
}'
curl --location --request POST 'https://gateway.luxpag.com/virtual-account/spei/quantity' \
--header 'Authorization: Basic Base64(appid:secret_key)' \
--header 'Content-Type: application/json' \
--data-raw '{
"app_id": "app_id",
"timestamp": "{{datetime}}"
}'
# Http Response (JSON format)
Parameter | Type | Description |
---|---|---|
code | string | return code |
msg | string | return msg |
sub_code | string | return sub code(only error) |
sub_msg | string | return sub msg(only error) |
account_id | string | Virtual Account ID |
account_number | string | Virtual Account(SPEI Clabe) |
provider | string | provider |
status | string | status;ACTIVE、CANCELED |
notify_url | string | IPN URL to merchant |
beneficiary_name | string | Service provider |
available_quantity | Integer | Number of available accounts |
# Return Code (Succes)
{
"code": "10000",
"msg": "Success",
"account_id": "{account_id}",
"account_number": "{account_number}",
"provider": "{provider}",
"status": "{status}",
"notify_url": "{notify_url}",
}
# Return Code (Fail)
{
"code": "40002",
"msg": "Business Failed",
"sub_code": "invalid-signature",
"sub_msg": "invalid signature"
}
# IPN Notifications
IPN (Instant Payment Notification) is a notification sent from one server to another through an HTTP POST request informing your transactions.
In order to receive notifications about the events in your platform, you have to previously configure the notification when you do the POST of the payment, indicating the URL in the field notify_url.
# Events
Whenever an event occurs, we will send you a notification in json format using HTTP POST to the URL that you specified.
We will notify the following events:
Action | Description |
---|---|
SUCCESS | trade succeeded |
Luxpag will send notifications with the following schedule of retries and confirmation awaiting times. You must return an HTTP STATUS 200 (OK) with reponse data "success" or "{"result":"success"}" before the corresponding time expires. If not, it will be assumed that you did not receive it correctly and you will be notified again.
Event | Time after the first dispatch |
---|---|
Dispatch | - |
1st retry | 10 minutes |
2nd retry | 30 minutes |
3rd retry | 60 minutes |
4th retry | 120 minutes |
5th retry | 360 minutes |
6th retry | 840 minutes |
# Notification Body (JSON format)
Parameter | Type | Required | Max Length(or Default Value) | Description |
---|---|---|---|---|
app_id | string | yes | 32 | created app's id at dashboard |
trade_no | string | yes | 64 | Luxpag trade NO. |
out_trade_no | string | yes | 64 | ID given by the merchant in their system |
out_request_no | string | no | 64 | refund number |
method | string | yes | 32 | Payment methods |
trade_status | string | yes | 16 | trade's status |
currency | string | yes | 3 | MXN for mexico |
amount | string | yes | request payment amount | |
user.name | string | no | user's name | |
user.email | string | no | user's email | |
user.phone | string | no | user's mobile phone number | |
user.identify.number | string | no | user's ID number | |
user.identify.type | string | no | user's ID type | |
card.card_no | string | no | card number | |
transfer_account.account_id | string | yes | virtual account's ID | |
transfer_account.account_number | string | yes | virtual account(SPEI Clabe) | |
transfer_account.provider | string | yes | virtual account's provider | |
transfer_account.buyer_id | string | yes | virtual account's merchant user's id | |
transfer_account.transfer_timestamp | string | yes | virtual account's timestamp | |
transfer_account.beneficiary_name | string | yes | virtual account's Service provider |
The notification sent has the following format:
Method: POST
Header:Content-Type: application/json
Header:Luxpag-Signature: hmacSHA256(payload, secret_key)
Body:
{
"amount":"",
"out_trade_no":"",
"method":"",
"trade_status":"",
"trade_no":"",
"currency":"",
"out_request_no":"",
"app_id":"",
"user":{
"identify":{
"number":"",
"type":""
},
"phone":"",
"email":""
},
"card":{
"card_no":"F6L4"
},
"transfer_account":{
"account_id":"",
"account_number":"",
"beneficiary_name":"",
"buyer_id":"",
"provider":"",
"transfer_timestamp":1669192513
}
}
payload:The data sent to the merchant by post, and the payload is JSON string.
# What should I do when I receive a notification?
When you receive a notification on your platform, Luxpag waits for a response to validate that you received it correctly. For this, you must return an HTTP STATUS 200 (OK) with reponse data "success" or "{"result":"success"}".
It is recommended that you respond to the notification before executing business logic or prior to accessing external resources so as not to exceed the estimated response times.
This communication is exclusively between the servers of Luxpag and your server, so there will not be a physical user seeing any type of result.
# Check Signature(Optional)
Luxpag includes a signature in the Luxpag-Signature header of each event. You can verify the signature to enhance security.
We will use the merchant's private key to encrypt the callback payload with hmacSHA256.
Header:Luxpag-Signature: SignHelper.hmacSHA256(payload, secret_key)
// Step 1
String payload = JSON.toJSONString(notify);
String sign = SignHelper.macSha256(payload, secret_key);
// Step 2
Header:Luxpag-Signature: 5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
/**
*
*/
public final class SignHelper{
/**
* HMAC with SHA-256
*
* @param content
* @param salt
* @return
*/
public static String macSha256(String content, String salt) {
StringBuilder result = new StringBuilder();
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(salt.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(content.getBytes(StandardCharsets.UTF_8));
for (byte b : hash) {
result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
}
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
}
return result.toString();
}
}
# Security Policy
Suggestion: Perform whitelist verification on the Luxpag callback service IP;
Suggestion: After receiving the successful IPN notification of the order, check back on Luxpag, especially for virtual account orders.