Appearance
Integration Guide
Integration Steps
- Register merchant access permissions on the platform
- Log in to the platform to view merchant key and iv
- Use the platform’s test APIs to complete gateway integration and API development/testing
- Contact our team in advance to whitelist your IP address
- After completing integration with the test server, contact our team to obtain the production merchant account and keys for replacement
- After switching to production, contact our team to whitelist the production IP address
Note: All API interactions must be transmitted over encrypted channels. If you encounter any issues, please contact the platform’s technical support team
Request Format Specification
Test Environment URL: https://t-api.nuvigopay.com
Production Environment URL: https://api.nuvigopay.com
Communication Protocol
The open platform communicates with merchants via HTTP POST requests. All responses are returned in JSON format. All amount-related fields must retain two decimal places.
Message Structure
All request and response character encoding uses UTF-8
- Request – Common Parameters (HTTP Headers):
| Field Name | Description | Type | Required | Remarks |
|---|---|---|---|---|
| X-Merchant-Code | Merchant Code | string | Yes | Assigned by the platform |
- Request – HTTP Body
| Field Name | Description | Type | Required | Remarks |
|---|---|---|---|---|
| content | Encrypted data | string | Yes | API request data encrypted before sending |
| timestamp | Timestamp | number | Yes | Current timestamp (milliseconds) |
- Receive response and decrypt content:
| Field Name | Description | Type | Required | Remarks | Example |
|---|---|---|---|---|---|
| code | Response Code | int | Yes | 200: Success; others indicate failure | |
| msg | Message | string | No | Error or status message | |
| data | Response Data | string | No | Detailed response result data |
Common Error Codes
Note: For different merchants, the description corresponding to the same code may vary slightly depending on business context.
| code | Description |
|---|---|
| 200 | Success |
| 9999 | Payout Failed |
| 6001 | Insufficient Balance |
| 7001 | Channel Closed |
| 1001 | Order Query Failed |
| 2000 | User Order Number is Required |
Signature Algorithm Description
Convert the request parameters into JSON, then encrypt them as the input parameters of the encryption algorithm.
java
import com.exception.BusinessException;
import lombok.experimental.UtilityClass;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.util.Base64;
@UtilityClass
public class aesutil {
private static final String AES = "AES";
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
private static Base64.Encoder base64Encoder = Base64.getEncoder();
private static Base64.Decoder base64Decoder = Base64.getDecoder();
static {
Security.setProperty("crypto.policy", "unlimited");
}
private static final String key = "The key can be viewed in the merchant dashboard.";
private static final String iv = "The IV can be viewed in the merchant dashboard";
public String encrypt(String content) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(), AES);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv.getBytes()));
byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);
byte[] byteAES = cipher.doFinal(byteEncode);
return base64Encoder.encodeToString(byteAES);
} catch (Exception e) {
throw new BusinessException("Encryption failed.");
}
}
public String decrypt(String content) {
try {
SecretKey secretKey = new SecretKeySpec(key.getBytes(), AES);
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv.getBytes()));
byte[] byteContent = base64Decoder.decode(content);
byte[] byteDecode = cipher.doFinal(byteContent);
return new String(byteDecode, StandardCharsets.UTF_8);
} catch (Exception e) {
throw new BusinessException("Decryption failed.");
}
}
public static void main(String[] args) {
String content = "hello world";
String encrypt = aesutil.encrypt(content);
System.out.println(encrypt);
String decrypt = aesutil.decrypt(encrypt);
System.out.println(decrypt);
}
}php
$key = '********************';
$iv = '**************';
function aes256CbcEncrypt($data)
{
global $iv, $key;
return base64_encode(openssl_encrypt($data, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv));
}
function aes256CbcDecrypt($encryptedData)
{
global $iv, $key;
return openssl_decrypt(base64_decode($encryptedData), 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
}go
// Global variables (can be replaced with configuration file loading or other methods).
var (
host = "https://api.******.com"
)
// AES-256-CBC Encrypt
func aes256CbcEncrypt(data []byte, merchant *ent.Merchant) (string, error) {
block, err := aes.NewCipher([]byte(merchant.Secret))
if err != nil {
return "", err
}
data = pkcs7Pad(data, aes.BlockSize)
cipherText := make([]byte, len(data))
mode := cipher.NewCBCEncrypter(block, []byte(merchant.Iv))
mode.CryptBlocks(cipherText, data)
return base64.StdEncoding.EncodeToString(cipherText), nil
}
// AES-256-CBC Decrypt
func aes256CbcDecrypt(encrypted string, merchant *ent.Merchant) ([]byte, error) {
cipherData, err := base64.StdEncoding.DecodeString(encrypted)
if err != nil {
return nil, err
}
block, err := aes.NewCipher([]byte(merchant.Secret))
if err != nil {
return nil, err
}
if len(cipherData)%aes.BlockSize != 0 {
return nil, fmt.Errorf("cipher data is not a multiple of the block size")
}
decrypted := make([]byte, len(cipherData))
mode := cipher.NewCBCDecrypter(block, []byte(merchant.Iv))
mode.CryptBlocks(decrypted, cipherData)
return pkcs7Unpad(decrypted)
}
// PKCS7 Fill
func pkcs7Pad(data []byte, blockSize int) []byte {
padding := blockSize - len(data)%blockSize
padText := bytes.Repeat([]byte{byte(padding)}, padding)
return append(data, padText...)
}
// PKCS7 Remove padding
func pkcs7Unpad(data []byte) ([]byte, error) {
length := len(data)
if length == 0 {
return nil, fmt.Errorf("data is empty")
}
padding := int(data[length-1])
if padding > length || padding == 0 {
return nil, fmt.Errorf("invalid padding")
}
return data[:length-padding], nil
}Request Example
java
private static final String Host = "https://**********.com";
public static void sendPost() throws IOException {
String url = "/*******/****";
String time = new SimpleDateFormat("yyyyMMddHHmmss").format(System.currentTimeMillis());
HttpRequest post = HttpUtil.createPost(Host + url);
Map<String, Object> re = new HashMap<String, Object>();
re.put("submitAmount", "2000");
re.put("currencyType", "BRL");
re.put("paymentType", "VA");
re.put("userOrderNumber", "dy"+time);
re.put("notifyUrl", "*********");
String content = aesutil.encrypt(JSONUtil.toJsonStr(re));
long timestamp = System.currentTimeMillis();
Map<String, Object> req = new HashMap<String, Object>();
req.put("content", content);
req.put("timestamp", timestamp);
post.header("X-Merchant-Code", "83272331");
post.body(JSONUtil.toJsonStr(req));
System.out.println(JSONUtil.toJsonStr(req));
HttpResponse execute = post.execute();
System.out.printf("post:" + post);
System.out.printf("result:" + execute.body());
ObjectMapper objectMapper = new ObjectMapper();
HolyPay response = objectMapper.readValue(execute.body(), HolyPay.class);
System.out.println("Decrypt:");
System.out.println("Decrypt: "+aesutil.decrypt(response.getData().getContent()));
}php
$host = '***********************';
$merchantId = (string)'**********************';
$key = '********************';
$iv = '**************';
function sendPost($action, $param)
{
global $merchantId, $iv, $key, $host;
$content = aes256CbcEncrypt(json_encode($param));
$timestamp = time();
$req = array(
"content" => $content,
"timestamp" => $timestamp
);
$ch = curl_init($host . $action);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json', 'X-Merchant-Code: ' . $merchantId,));
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($req));
$response = curl_exec($ch);
if ($response === false) {
echo "Error: " . curl_error($ch);
} else {
echo "post: The request information is difficult to simulate and output directly\n";
echo "result: " . $response . "\n";
}
curl_close($ch);
return $response;
}go
// Global variables (can be replaced with configuration file loading or other approaches)
var (
host = "https://api.******.com"
)
type PayRes struct {
Code int `json:"code"`
Data BussinessData `json:"data"`
Msg string `json:"msg"`
}
type BussinessData struct {
Content string `json:"content"`
Timestamp int64 `json:"timestamp"`
}
// Send a POST request
func sendPost(action string, param map[string]interface{}, merchant *ent.Merchant) (*BussinessData, error) {
jsonData, err := json.Marshal(param)
if err != nil {
return nil, err
}
log.Info().Msg(string(jsonData))
content, err := aes256CbcEncrypt(jsonData, merchant)
if err != nil {
return nil, err
}
reqBody := map[string]interface{}{
"content": content,
"timestamp": time.Now().Unix(),
}
bodyBytes, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
url := host + action
req, err := http.NewRequest("POST", url, bytes.NewBuffer(bodyBytes))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Merchant-Code", merchant.MerchantsNumber)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
log.Info().Msg(string(respBody))
log.Info().Msg(strconv.Itoa(resp.StatusCode))
// Parse the response JSON
var returnData PayRes
err = json.Unmarshal([]byte(respBody), &returnData)
if err != nil {
fmt.Println("Failed to parse the response:", err)
return nil, err
}
log.Info().Interface("returnData", returnData).Msg("<UNK>")
if returnData.Code != 200 {
return nil, errors.New(returnData.Msg)
}
return &returnData.Data, nil
}Merchant Balance Inquiry
URL
POST /proxyPayQuery/balance
Request Parameters
| Field Name | Description | Type | Max Length | Required | Remarks | Example |
|---|---|---|---|---|---|---|
| currencyType | Currency type | string | 50 | Yes | See currency codes below | BRL |
Response Parameters
| Field Name | Description | Type | Max Length | Required | Remarks | Example |
|---|---|---|---|---|---|---|
| usableAmount | Available Account Balance | string | 12 | Yes | Two decimal places | 100.00 |
Currency Codes
!!! Do NOT modify letter case of the currency codes !!!
- Brazil(BRL)