VPayAPI v1.0

VPay API Documentation

Fast, Secure, and Reliable Payment Solution

API Features
  • RESTful API design, simple and easy to use
  • Supports PHP, Python, Golang and more
  • Complete payment flow: payment, query, disbursement, etc.
  • Real-time callback notification
  • RSA signature verification

Basic Rules

Request URL

Production Environment:

https://api.vpayid.com/vpayid-api
Request Method
POST
Content-Type
application/json
Signature Algorithm

Generating sign: Build the plaintext string src by concatenating the fields defined in the "Signature Rule" of each API, take its UTF-8 bytes, then perform a PKCS#1 v1.5 (type1) raw signing with the merchant RSA private key (signature padding block 0x00 0x01 FF..FF 0x00 + src, i.e. c = block^d mod n), and Base64 encode the result to get sign. This is NOT SHA256withRSA digest signing (do not use Signature/openssl_sign).

Verification: The platform recomputes sign with the merchant RSA public key in the same way (type1), recovering the 0x00 0x01 FF..FF 0x00 src block, and compares it byte-by-byte with the plaintext string src. It passes only when they are identical.

RSA Key Generation

Generate the Merchant RSA Key Pair (OpenSSL)
RSA 2048-bit is recommended. The private key must be in PKCS#8 format.

1) Generate the private key (PKCS#8, header BEGIN PRIVATE KEY, works on all OpenSSL versions):

openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out rsa_private_pkcs8.pem

2) Export the public key from the private key (X.509/SPKI, header BEGIN PUBLIC KEY):

openssl rsa -in rsa_private_pkcs8.pem -pubout -out rsa_public.pem

Note: on OpenSSL 3.x, openssl genrsa -out rsa_pkcs1_private.pem 2048 actually already outputs PKCS#8 (BEGIN PRIVATE KEY); but on OpenSSL 1.x genrsa outputs PKCS#1 (BEGIN RSA PRIVATE KEY), which the Java platform cannot load directly (algid parse error). It must be converted to PKCS#8 first:

openssl genrsa -out rsa_pkcs1_private.pem 2048
openssl pkcs8 -topk8 -nocrypt -in rsa_pkcs1_private.pem -out rsa_private_pkcs8.pem
openssl rsa -in rsa_pkcs1_private.pem -pubout -out rsa_public.pem
Key Format Requirements
  • Private key: must be PKCS#8 (-----BEGIN PRIVATE KEY-----). PKCS#1 (BEGIN RSA PRIVATE KEY) cannot be loaded.
  • Public key: X.509/SPKI format (-----BEGIN PUBLIC KEY-----). When submitting to the platform, provide only the Base64 body (without the header/footer lines or line breaks).
  • Keep the private key safe by the merchant — never disclose it or commit it to a repository; submit the public key to the platform for your merchant profile.
Self-Check the Key Pair (Simulating Platform Verification)
Same logic as platform verification: private-key signing → public-key decrypt and compare the plaintext.

Taking the Payment API as an example, the plaintext src = amount + callbackUrl + channelCode + merchantCode + orderNumber (no line breaks):

printf '%s' "100000http://localhost/callbackQRISTEST1604384758793" > src.txt

# Sign with the private key (PKCS#1 v1.5 type1) to get sign
openssl pkeyutl -sign -inkey rsa_private_pkcs8.pem -in src.txt -out sign.bin
openssl base64 -in sign.bin   # Base64 of this is the sign field in the request

# Verify with the public key (simulating the platform). "Signature Verified Successfully" means the pair matches
openssl pkeyutl -verify -pubin -inkey rsa_public.pem -in src.txt -sigfile sign.bin

You can also verify using the self-check methods in the code examples below.

How the Keys Are Used
  • Request signing: the merchant signs the plaintext src with its own RSA private key using PKCS#1 v1.5 (type1) raw signing, Base64 encodes it, and puts it into the sign field (signType=RSA). This is NOT SHA256withRSA digest signing.
  • Platform verification: the platform decrypts sign with the merchant's submitted RSA public key and compares it with the plaintext.
  • Async callback verification: the rsaSign in platform callbacks is verified by decrypting with the platform public key (please contact the platform to obtain it).

Payment API

API URL: /payment
Create new payment order
POST

Request Parameters

Parameter NameDescriptionTypeRequiredExample
merchantCodeMerchant CodeStringYtest
orderNumberOrder NumberStringY1604384758793
amountAmountIntegerY40000
phonePhoneStringY08123456789
emailEmailStringYtest@test.com
userNameNameStringYJohn Doe
walletNumberWallet NumberStringN08821900000 (Required for DANA, format 08********; Required for OVO cashier with real number, otherwise optional)
channelCodeChannel CodeStringYM1 (If CASH, will use cashier payment. See channel code table for other codes)
returnUrlReturn URLStringNhttp://test/return
callbackUrlCallback URLStringYhttp://test/callback
signTypeSignature TypeStringYRSA
signSignatureStringYRSA(...)

Signature Rule

RSA(amount + callbackUrl + channelCode + merchantCode + orderNumber)

Response Parameters

Parameter NameDescriptionTypeExample
codeResponse CodeString000
messageResponse MessageStringsuccess
orderNumberOrder IDStringO3915CB3C93E445C9
accountNumberBank AccountStringTEST0001 (VA only)
paymentUrlPayment URLStringhttp://xxx.xxx/
qrcodeQR CodeStringReturned for QRIS payment
merchantCodeMerchant CodeStringtest

Request Example

{
  "merchantCode": "test",
  "orderNumber": "1604384758793",
  "amount": 40000,
  "phone": "08123456789",
  "email": "test@test.com",
  "userName": "John Doe",
  "channelCode": "M1",
  "returnUrl": "http://test/return",
  "callbackUrl": "http://test/callback",
  "sign": "a1b2c3d4e5f6..."
}

Response Example

{
  "code": "000",
  "message": "success",
  "orderNumber": "O3915CB3C93E445C9",
  "paymentUrl": "http://xxx.xxx/",
  "qrcode": "data:image/png;base64,..."
}
Code Examples
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * VPay /payment example (pure JDK, no third-party dependency).
 *
 * 1. PRIVATE_KEY_PATH is your merchant RSA private key (PKCS#8);
 *    PUBLIC_KEY_PATH is your merchant RSA public key (X.509) for self-verification.
 * 2. sign = the merchant RSA private key does a PKCS#1 v1.5 type1 raw signing on src
 *    (signature padding block 0x00 0x01 FF..FF 0x00 + src, then c = block^d mod n)
 *    and Base64 encodes it. The platform verifies it by recomputing with the merchant
 *    RSA public key (type1) and comparing the recovered bytes with src.
 *    NOT SHA256withRSA (do not use Signature).
 */
public class PaymentDemo {

    static final String BASE_URL = "https://api.vpayid.com/vpayid-api";
    static final String PRIVATE_KEY_PATH = "YOUR_PRIVATE_KEY.pem"; // your PKCS#8 private key
    static final String PUBLIC_KEY_PATH = "YOUR_PUBLIC_KEY.pem";   // your X.509 public key
    static final String MERCHANT_CODE = "YOUR_MERCHANT_CODE";
    static final String CALLBACK_URL = "http://localhost/callback";
    public static void main(String[] args) throws Exception {
        String orderNumber = "PAY_" + System.currentTimeMillis();
        int amount = 100000;

        // src = amount + callbackUrl + channelCode + merchantCode + orderNumber
        String src = amount + CALLBACK_URL + "QRIS" + MERCHANT_CODE + orderNumber;

        PrivateKey priv = loadPrivateKey(PRIVATE_KEY_PATH);
        String sign = rsaPrivateEncryptBase64(src, priv);
        boolean ok = rsaPublicDecryptVerify(src, sign, loadPublicKey(PUBLIC_KEY_PATH)); // self-check like the platform

        Map<String, Object> payload = new LinkedHashMap<>();
        payload.put("merchantCode", MERCHANT_CODE);
        payload.put("orderNumber", orderNumber);
        payload.put("amount", amount);
        payload.put("phone", "08123456789");
        payload.put("email", "test@test.com");
        payload.put("userName", "John Doe");
        payload.put("channelCode", "QRIS");
        payload.put("callbackUrl", CALLBACK_URL);
        payload.put("signType", "RSA");
        payload.put("sign", sign);

        String body = toJson(payload);
        System.out.println("src     = " + src);
        System.out.println("selfVerify = " + ok);
        System.out.println("request = " + body);
        // optional: POST BASE_URL + "/payment" with body
    }

    /**
     * PKCS#1 v1.5 type1 raw signing of src with the merchant private key
     * -> Base64 (the required sign).
     */
    static String rsaPrivateEncryptBase64(String src, PrivateKey privateKey) {
        RSAPrivateKey rsaPriv = (RSAPrivateKey) privateKey;
        int k = rsaPriv.getModulus().bitLength() / 8;
        byte[] data = src.getBytes(StandardCharsets.UTF_8);
        if (data.length > k - 11) throw new IllegalArgumentException("src is too long");
        byte[] block = new byte[k];
        block[0] = 0x00; block[1] = 0x01;                     // type1: 00 01 FF..FF 00 src
        java.util.Arrays.fill(block, 2, k - data.length - 1, (byte) 0xFF);
        block[k - data.length - 1] = 0x00;
        System.arraycopy(data, 0, block, k - data.length, data.length);
        BigInteger m = new BigInteger(1, block);
        BigInteger c = m.modPow(rsaPriv.getPrivateExponent(), rsaPriv.getModulus());
        byte[] sig = c.toByteArray();
        if (sig.length == k + 1 && sig[0] == 0) sig = java.util.Arrays.copyOfRange(sig, 1, k + 1); // strip BigInteger sign byte
        if (sig.length > k) throw new IllegalStateException("signature is too long");
        byte[] out = new byte[k];
        System.arraycopy(sig, 0, out, k - sig.length, sig.length);
        return Base64.getEncoder().encodeToString(out);
    }

    /**
     * Self-check like the platform: recompute with the public key (type1),
     * src is recovered from 0x00 0x01 FF..FF 0x00 src when valid.
     */
    static boolean rsaPublicDecryptVerify(String src, String sign, PublicKey publicKey) {
        try {
            RSAPublicKey rsaPub = (RSAPublicKey) publicKey;
            int k = rsaPub.getModulus().bitLength() / 8;
            byte[] sig = Base64.getDecoder().decode(sign);
            BigInteger c = new BigInteger(1, sig);
            BigInteger m = c.modPow(rsaPub.getPublicExponent(), rsaPub.getModulus());
            byte[] pad = new byte[k];
            byte[] mb = m.toByteArray();
            System.arraycopy(mb, 0, pad, k - mb.length, mb.length);
            if (pad[0] != 0x00 || pad[1] != 0x01) return false;   // needs 00 01 FF..00 data
            int sep = -1;
            for (int i = 2; i < k; i++) {
                if (pad[i] == 0x00) { sep = i; break; }
            }
            if (sep < 0) return false;
            return src.equals(new String(pad, sep + 1, k - sep - 1, StandardCharsets.UTF_8));
        } catch (Exception e) {
            return false;
        }
    }

    // load PKCS#8 private key from a PEM file
    static PrivateKey loadPrivateKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // load X.509 public key from a PEM file (for self-verification)
    static PublicKey loadPublicKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // minimal JSON builder (or use any JSON library)
    static String toJson(Map<String, Object> m) {
        StringBuilder sb = new StringBuilder("{");
        boolean first = true;
        for (Map.Entry<String, Object> e : m.entrySet()) {
            if (!first) sb.append(",");
            first = false;
            sb.append("\"").append(e.getKey()).append("\":");
            Object v = e.getValue();
            if (v instanceof Number) {
                sb.append(v);
            } else {
                sb.append("\"").append(v).append("\"");
            }
        }
        return sb.append("}").toString();
    }

}

Payment Query

API URL: /checkPayment
Query payment order status
POST

Request Parameters

Parameter NameDescriptionTypeRequiredExample
merchantCodeMerchant CodeStringYtest
orderNumberOrder NumberStringY1604384758793
signTypeSignature TypeStringYRSA
signSignatureStringYRSA(...)

Signature Rule

RSA(merchantCode + orderNumber)

Response Parameters

Parameter NameDescriptionTypeExample
codeResponse CodeString000
messageResponse MessageStringcomplete
userOrderNumberUser Order NumberString1604384968942
orderNumberPlatform Order NumberStringtest16043849702603
amountPayment AmountInteger40000
merchantCodeMerchant CodeStringtest
phonePhoneStringHidden (00)
emailEmailStringHidden (00)
userNameNameStringJohn Doe
channelCodeChannel CodeStringM1
statusPayment Statusint0 Pending, 1 Success, 2 Failed
createTimeOrder Create TimeDate2020-11-03 13:29:30
payTimePayment TimeDate2020-11-03 13:39:30 (Returned on success)

Request Example

{
  "merchantCode": "test",
  "orderNumber": "1604384758793",
  "sign": "a1b2c3d4e5f6..."
}

Response Example

{
  "code": "000",
  "status": 1,
  "amount": 40000
}
Code Examples
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * VPay /checkPayment example (pure JDK, no third-party dependency).
 *
 * 1. PRIVATE_KEY_PATH is your merchant RSA private key (PKCS#8);
 *    PUBLIC_KEY_PATH is your merchant RSA public key (X.509) for self-verification.
 * 2. sign = the merchant RSA private key does a PKCS#1 v1.5 type1 raw signing on src
 *    (signature padding block 0x00 0x01 FF..FF 0x00 + src, then c = block^d mod n)
 *    and Base64 encodes it. The platform verifies it by recomputing with the merchant
 *    RSA public key (type1) and comparing the recovered bytes with src.
 *    NOT SHA256withRSA (do not use Signature).
 */
public class CheckPaymentDemo {

    static final String BASE_URL = "https://api.vpayid.com/vpayid-api";
    static final String PRIVATE_KEY_PATH = "YOUR_PRIVATE_KEY.pem"; // your PKCS#8 private key
    static final String PUBLIC_KEY_PATH = "YOUR_PUBLIC_KEY.pem";   // your X.509 public key
    static final String MERCHANT_CODE = "YOUR_MERCHANT_CODE";

    public static void main(String[] args) throws Exception {
        String orderNumber = "PAY_" + System.currentTimeMillis();

        // src = merchantCode + orderNumber
        String src = MERCHANT_CODE + orderNumber;

        PrivateKey priv = loadPrivateKey(PRIVATE_KEY_PATH);
        String sign = rsaPrivateEncryptBase64(src, priv);
        boolean ok = rsaPublicDecryptVerify(src, sign, loadPublicKey(PUBLIC_KEY_PATH)); // self-check like the platform

        Map<String, Object> payload = new LinkedHashMap<>();
        payload.put("merchantCode", MERCHANT_CODE);
        payload.put("orderNumber", orderNumber);
        payload.put("signType", "RSA");
        payload.put("sign", sign);

        String body = toJson(payload);
        System.out.println("src     = " + src);
        System.out.println("selfVerify = " + ok);
        System.out.println("request = " + body);
        // optional: POST BASE_URL + "/checkPayment" with body
    }

    /**
     * PKCS#1 v1.5 type1 raw signing of src with the merchant private key
     * -> Base64 (the required sign).
     */
    static String rsaPrivateEncryptBase64(String src, PrivateKey privateKey) {
        RSAPrivateKey rsaPriv = (RSAPrivateKey) privateKey;
        int k = rsaPriv.getModulus().bitLength() / 8;
        byte[] data = src.getBytes(StandardCharsets.UTF_8);
        if (data.length > k - 11) throw new IllegalArgumentException("src is too long");
        byte[] block = new byte[k];
        block[0] = 0x00; block[1] = 0x01;                     // type1: 00 01 FF..FF 00 src
        java.util.Arrays.fill(block, 2, k - data.length - 1, (byte) 0xFF);
        block[k - data.length - 1] = 0x00;
        System.arraycopy(data, 0, block, k - data.length, data.length);
        BigInteger m = new BigInteger(1, block);
        BigInteger c = m.modPow(rsaPriv.getPrivateExponent(), rsaPriv.getModulus());
        byte[] sig = c.toByteArray();
        if (sig.length == k + 1 && sig[0] == 0) sig = java.util.Arrays.copyOfRange(sig, 1, k + 1); // strip BigInteger sign byte
        if (sig.length > k) throw new IllegalStateException("signature is too long");
        byte[] out = new byte[k];
        System.arraycopy(sig, 0, out, k - sig.length, sig.length);
        return Base64.getEncoder().encodeToString(out);
    }

    /**
     * Self-check like the platform: recompute with the public key (type1),
     * src is recovered from 0x00 0x01 FF..FF 0x00 src when valid.
     */
    static boolean rsaPublicDecryptVerify(String src, String sign, PublicKey publicKey) {
        try {
            RSAPublicKey rsaPub = (RSAPublicKey) publicKey;
            int k = rsaPub.getModulus().bitLength() / 8;
            byte[] sig = Base64.getDecoder().decode(sign);
            BigInteger c = new BigInteger(1, sig);
            BigInteger m = c.modPow(rsaPub.getPublicExponent(), rsaPub.getModulus());
            byte[] pad = new byte[k];
            byte[] mb = m.toByteArray();
            System.arraycopy(mb, 0, pad, k - mb.length, mb.length);
            if (pad[0] != 0x00 || pad[1] != 0x01) return false;   // needs 00 01 FF..00 data
            int sep = -1;
            for (int i = 2; i < k; i++) {
                if (pad[i] == 0x00) { sep = i; break; }
            }
            if (sep < 0) return false;
            return src.equals(new String(pad, sep + 1, k - sep - 1, StandardCharsets.UTF_8));
        } catch (Exception e) {
            return false;
        }
    }

    // load PKCS#8 private key from a PEM file
    static PrivateKey loadPrivateKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // load X.509 public key from a PEM file (for self-verification)
    static PublicKey loadPublicKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // minimal JSON builder (or use any JSON library)
    static String toJson(Map<String, Object> m) {
        StringBuilder sb = new StringBuilder("{");
        boolean first = true;
        for (Map.Entry<String, Object> e : m.entrySet()) {
            if (!first) sb.append(",");
            first = false;
            sb.append("\"").append(e.getKey()).append("\":");
            Object v = e.getValue();
            if (v instanceof Number) {
                sb.append(v);
            } else {
                sb.append("\"").append(v).append("\"");
            }
        }
        return sb.append("}").toString();
    }

}

Disbursement API

API URL: /disbursement
Initiate Disbursement Request
POST

Request Parameters

Parameter NameDescriptionTypeRequiredExample
merchantCodeMerchant CodeStringYtest
orderNumberOrder NumberStringY1604384758793
amountAmountIntegerY40000
bankAccountBank AccountStringY100100100
bankCodeBank CodeStringYPERMATA
phonePhoneStringY08123456789
emailEmailStringYtest@test.com
userNameRecipient NameStringYJohn Doe
channelCodeChannel CodeStringYALL
returnUrlReturn URLStringNhttp://test/return
callbackUrlCallback URLStringYhttp://test/callback
signTypeSignature TypeStringYRSA
signSignatureStringYRSA(amount + bankAccount + bankCode + callbackUrl + channelCode + merchantCode + orderNumber)

Signature Rule

RSA(amount + bankAccount + bankCode + callbackUrl + channelCode + merchantCode + orderNumber)

PS

channelCode available: ALL for all channels, ID IDN US ZH for different countries, use ALL if not specified

Synchronous response: "code": "000" means success, any other value means the submission failed

If the request times out, you must use the query API to verify the order status

The final order status is subject to the query result or the "status" field of the asynchronous callback

Request Example

{
  "merchantCode": "test",
  "orderNumber": "1604384758793",
  "amount": 50000,
  "bankAccount": "1234567890",
  "bankCode": "BCA",
  "phone": "08123456789",
  "email": "test@test.com",
  "userName": "John Doe",
  "channelCode": "ALL",
  "returnUrl": "http://test/return",
  "callbackUrl": "http://test/callback",
  "sign": "a1b2c3d4e5f6..."
}

Response Example

{
  "code": "000",
  "message": "success",
  "amount": 40000,
  "merchantCode": "test"
}
Code Examples
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * VPay /disbursement example (pure JDK, no third-party dependency).
 *
 * 1. PRIVATE_KEY_PATH is your merchant RSA private key (PKCS#8);
 *    PUBLIC_KEY_PATH is your merchant RSA public key (X.509) for self-verification.
 * 2. sign = the merchant RSA private key does a PKCS#1 v1.5 type1 raw signing on src
 *    (signature padding block 0x00 0x01 FF..FF 0x00 + src, then c = block^d mod n)
 *    and Base64 encodes it. The platform verifies it by recomputing with the merchant
 *    RSA public key (type1) and comparing the recovered bytes with src.
 *    NOT SHA256withRSA (do not use Signature).
 */
public class DisbursementDemo {

    static final String BASE_URL = "https://api.vpayid.com/vpayid-api";
    static final String PRIVATE_KEY_PATH = "YOUR_PRIVATE_KEY.pem"; // your PKCS#8 private key
    static final String PUBLIC_KEY_PATH = "YOUR_PUBLIC_KEY.pem";   // your X.509 public key
    static final String MERCHANT_CODE = "YOUR_MERCHANT_CODE";
    static final String CALLBACK_URL = "http://localhost/callback";
    public static void main(String[] args) throws Exception {
        String orderNumber = "OUT_" + System.currentTimeMillis();
        int amount = 1000000;
        String bankAccount = "7550390595";
        String bankCode = "BCA";

        // src = amount + bankAccount + bankCode + callbackUrl + channelCode + merchantCode + orderNumber
        String src = amount + bankAccount + bankCode + CALLBACK_URL + "ALL" + MERCHANT_CODE + orderNumber;

        PrivateKey priv = loadPrivateKey(PRIVATE_KEY_PATH);
        String sign = rsaPrivateEncryptBase64(src, priv);
        boolean ok = rsaPublicDecryptVerify(src, sign, loadPublicKey(PUBLIC_KEY_PATH)); // self-check like the platform

        Map<String, Object> payload = new LinkedHashMap<>();
        payload.put("merchantCode", MERCHANT_CODE);
        payload.put("orderNumber", orderNumber);
        payload.put("amount", amount);
        payload.put("bankAccount", bankAccount);
        payload.put("bankCode", bankCode);
        payload.put("phone", "08000000000");
        payload.put("email", "noreply@test.com");
        payload.put("userName", "Fandi");
        payload.put("channelCode", "ALL");
        payload.put("callbackUrl", CALLBACK_URL);
        payload.put("signType", "RSA");
        payload.put("sign", sign);

        String body = toJson(payload);
        System.out.println("src     = " + src);
        System.out.println("selfVerify = " + ok);
        System.out.println("request = " + body);
        // optional: POST BASE_URL + "/disbursement" with body
    }

    /**
     * PKCS#1 v1.5 type1 raw signing of src with the merchant private key
     * -> Base64 (the required sign).
     */
    static String rsaPrivateEncryptBase64(String src, PrivateKey privateKey) {
        RSAPrivateKey rsaPriv = (RSAPrivateKey) privateKey;
        int k = rsaPriv.getModulus().bitLength() / 8;
        byte[] data = src.getBytes(StandardCharsets.UTF_8);
        if (data.length > k - 11) throw new IllegalArgumentException("src is too long");
        byte[] block = new byte[k];
        block[0] = 0x00; block[1] = 0x01;                     // type1: 00 01 FF..FF 00 src
        java.util.Arrays.fill(block, 2, k - data.length - 1, (byte) 0xFF);
        block[k - data.length - 1] = 0x00;
        System.arraycopy(data, 0, block, k - data.length, data.length);
        BigInteger m = new BigInteger(1, block);
        BigInteger c = m.modPow(rsaPriv.getPrivateExponent(), rsaPriv.getModulus());
        byte[] sig = c.toByteArray();
        if (sig.length == k + 1 && sig[0] == 0) sig = java.util.Arrays.copyOfRange(sig, 1, k + 1); // strip BigInteger sign byte
        if (sig.length > k) throw new IllegalStateException("signature is too long");
        byte[] out = new byte[k];
        System.arraycopy(sig, 0, out, k - sig.length, sig.length);
        return Base64.getEncoder().encodeToString(out);
    }

    /**
     * Self-check like the platform: recompute with the public key (type1),
     * src is recovered from 0x00 0x01 FF..FF 0x00 src when valid.
     */
    static boolean rsaPublicDecryptVerify(String src, String sign, PublicKey publicKey) {
        try {
            RSAPublicKey rsaPub = (RSAPublicKey) publicKey;
            int k = rsaPub.getModulus().bitLength() / 8;
            byte[] sig = Base64.getDecoder().decode(sign);
            BigInteger c = new BigInteger(1, sig);
            BigInteger m = c.modPow(rsaPub.getPublicExponent(), rsaPub.getModulus());
            byte[] pad = new byte[k];
            byte[] mb = m.toByteArray();
            System.arraycopy(mb, 0, pad, k - mb.length, mb.length);
            if (pad[0] != 0x00 || pad[1] != 0x01) return false;   // needs 00 01 FF..00 data
            int sep = -1;
            for (int i = 2; i < k; i++) {
                if (pad[i] == 0x00) { sep = i; break; }
            }
            if (sep < 0) return false;
            return src.equals(new String(pad, sep + 1, k - sep - 1, StandardCharsets.UTF_8));
        } catch (Exception e) {
            return false;
        }
    }

    // load PKCS#8 private key from a PEM file
    static PrivateKey loadPrivateKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // load X.509 public key from a PEM file (for self-verification)
    static PublicKey loadPublicKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // minimal JSON builder (or use any JSON library)
    static String toJson(Map<String, Object> m) {
        StringBuilder sb = new StringBuilder("{");
        boolean first = true;
        for (Map.Entry<String, Object> e : m.entrySet()) {
            if (!first) sb.append(",");
            first = false;
            sb.append("\"").append(e.getKey()).append("\":");
            Object v = e.getValue();
            if (v instanceof Number) {
                sb.append(v);
            } else {
                sb.append("\"").append(v).append("\"");
            }
        }
        return sb.append("}").toString();
    }

}

Disbursement Query

API URL: /checkDisbursement
Query disbursement order status
POST

Request Parameters

Parameter NameDescriptionTypeRequiredExample
merchantCodeMerchant CodeStringYtest
orderNumberOrder NumberStringY1604384758793
signTypeSignature TypeStringYRSA
signSignatureStringYRSA(...)

Signature Rule

RSA(merchantCode + orderNumber)

Request Example

{
  "merchantCode": "test",
  "orderNumber": "1604384758793",
  "sign": "a1b2c3d4e5f6..."
}

Response Example

{
  "code": "000",
  "message": "complete",
  "userOrderNumber": "1604384968942",
  "orderNumber": "test16043849702603",
  "amount": 40000,
  "merchantCode": "test",
  "phone": "00",
  "email": "00",
  "userName": "John Doe",
  "bankCode": "PERMATA",
  "bankAccount": "100100100",
  "channelCode": "M1",
  "status": 1,
  "createTime": "2020-11-03 13:29:30",
  "payTime": "2020-11-03 13:39:30"
}
Code Examples
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * VPay /checkDisbursement example (pure JDK, no third-party dependency).
 *
 * 1. PRIVATE_KEY_PATH is your merchant RSA private key (PKCS#8);
 *    PUBLIC_KEY_PATH is your merchant RSA public key (X.509) for self-verification.
 * 2. sign = the merchant RSA private key does a PKCS#1 v1.5 type1 raw signing on src
 *    (signature padding block 0x00 0x01 FF..FF 0x00 + src, then c = block^d mod n)
 *    and Base64 encodes it. The platform verifies it by recomputing with the merchant
 *    RSA public key (type1) and comparing the recovered bytes with src.
 *    NOT SHA256withRSA (do not use Signature).
 */
public class CheckDisbursementDemo {

    static final String BASE_URL = "https://api.vpayid.com/vpayid-api";
    static final String PRIVATE_KEY_PATH = "YOUR_PRIVATE_KEY.pem"; // your PKCS#8 private key
    static final String PUBLIC_KEY_PATH = "YOUR_PUBLIC_KEY.pem";   // your X.509 public key
    static final String MERCHANT_CODE = "YOUR_MERCHANT_CODE";

    public static void main(String[] args) throws Exception {
        String orderNumber = "OUT_" + System.currentTimeMillis();

        // src = merchantCode + orderNumber
        String src = MERCHANT_CODE + orderNumber;

        PrivateKey priv = loadPrivateKey(PRIVATE_KEY_PATH);
        String sign = rsaPrivateEncryptBase64(src, priv);
        boolean ok = rsaPublicDecryptVerify(src, sign, loadPublicKey(PUBLIC_KEY_PATH)); // self-check like the platform

        Map<String, Object> payload = new LinkedHashMap<>();
        payload.put("merchantCode", MERCHANT_CODE);
        payload.put("orderNumber", orderNumber);
        payload.put("signType", "RSA");
        payload.put("sign", sign);

        String body = toJson(payload);
        System.out.println("src     = " + src);
        System.out.println("selfVerify = " + ok);
        System.out.println("request = " + body);
        // optional: POST BASE_URL + "/checkDisbursement" with body
    }

    /**
     * PKCS#1 v1.5 type1 raw signing of src with the merchant private key
     * -> Base64 (the required sign).
     */
    static String rsaPrivateEncryptBase64(String src, PrivateKey privateKey) {
        RSAPrivateKey rsaPriv = (RSAPrivateKey) privateKey;
        int k = rsaPriv.getModulus().bitLength() / 8;
        byte[] data = src.getBytes(StandardCharsets.UTF_8);
        if (data.length > k - 11) throw new IllegalArgumentException("src is too long");
        byte[] block = new byte[k];
        block[0] = 0x00; block[1] = 0x01;                     // type1: 00 01 FF..FF 00 src
        java.util.Arrays.fill(block, 2, k - data.length - 1, (byte) 0xFF);
        block[k - data.length - 1] = 0x00;
        System.arraycopy(data, 0, block, k - data.length, data.length);
        BigInteger m = new BigInteger(1, block);
        BigInteger c = m.modPow(rsaPriv.getPrivateExponent(), rsaPriv.getModulus());
        byte[] sig = c.toByteArray();
        if (sig.length == k + 1 && sig[0] == 0) sig = java.util.Arrays.copyOfRange(sig, 1, k + 1); // strip BigInteger sign byte
        if (sig.length > k) throw new IllegalStateException("signature is too long");
        byte[] out = new byte[k];
        System.arraycopy(sig, 0, out, k - sig.length, sig.length);
        return Base64.getEncoder().encodeToString(out);
    }

    /**
     * Self-check like the platform: recompute with the public key (type1),
     * src is recovered from 0x00 0x01 FF..FF 0x00 src when valid.
     */
    static boolean rsaPublicDecryptVerify(String src, String sign, PublicKey publicKey) {
        try {
            RSAPublicKey rsaPub = (RSAPublicKey) publicKey;
            int k = rsaPub.getModulus().bitLength() / 8;
            byte[] sig = Base64.getDecoder().decode(sign);
            BigInteger c = new BigInteger(1, sig);
            BigInteger m = c.modPow(rsaPub.getPublicExponent(), rsaPub.getModulus());
            byte[] pad = new byte[k];
            byte[] mb = m.toByteArray();
            System.arraycopy(mb, 0, pad, k - mb.length, mb.length);
            if (pad[0] != 0x00 || pad[1] != 0x01) return false;   // needs 00 01 FF..00 data
            int sep = -1;
            for (int i = 2; i < k; i++) {
                if (pad[i] == 0x00) { sep = i; break; }
            }
            if (sep < 0) return false;
            return src.equals(new String(pad, sep + 1, k - sep - 1, StandardCharsets.UTF_8));
        } catch (Exception e) {
            return false;
        }
    }

    // load PKCS#8 private key from a PEM file
    static PrivateKey loadPrivateKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // load X.509 public key from a PEM file (for self-verification)
    static PublicKey loadPublicKey(String pemPath) throws Exception {
        String pem = new String(Files.readAllBytes(Paths.get(pemPath)), StandardCharsets.UTF_8)
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        return keyFactory.generatePublic(new X509EncodedKeySpec(Base64.getMimeDecoder().decode(pem)));
    }

    // minimal JSON builder (or use any JSON library)
    static String toJson(Map<String, Object> m) {
        StringBuilder sb = new StringBuilder("{");
        boolean first = true;
        for (Map.Entry<String, Object> e : m.entrySet()) {
            if (!first) sb.append(",");
            first = false;
            sb.append("\"").append(e.getKey()).append("\":");
            Object v = e.getValue();
            if (v instanceof Number) {
                sb.append(v);
            } else {
                sb.append("\"").append(v).append("\"");
            }
        }
        return sb.append("}").toString();
    }

}

Available Channels

API URL: /queryChannel
Query available payment channels
POST

Request Parameters

Parameter NameDescriptionTypeRequiredExample
merchantCodeMerchant CodeStringYtest
timestampTimestampStringY1604384758793
signTypeSignature TypeStringYRSA
signSignatureStringYRSA(merchantCode + timestamp)

Response Parameters

Parameter NameDescriptionTypeExample
codeResponse CodeString000
messageResponse MessageStringquery success
channelCodeListChannel ListLIST
- channelCodeChannel CodeStringBT
- channelTypeChannel TypeInteger0 Payment 1 Disbursement
- channelRateChannel RateDouble7.0
- channelFeeChannel FeeInteger200

Signature Rule

RSA(merchantCode + timestamp)

Request Example

{
  "merchantCode": "test",
  "timestamp": 1604384758793,
  "sign": "a1b2c3d4e5f6..."
}

Response Example

{
  "code": "000",
  "channels": [
    {
      "channelCode": "M1",
      "channelName": "QRIS",
      "minAmount": 1000,
      "maxAmount": 10000000
    }
  ]
}

Balance Query

API URL: /checkBalance
Query merchant balance
POST

Request Parameters

Parameter NameDescriptionTypeRequiredExample
merchantCodeMerchant CodeStringYtest
timestampTimestampStringY1604384758793
signTypeSignature TypeStringYRSA
signSignatureStringYRSA(merchantCode + timestamp)

Response Parameters

Parameter NameDescriptionTypeExample
codeResponse CodeString000
messageResponse MessageStringbalance query success
merchantCodeMerchant CodeString1604384968942
merchantBlanceMerchant BalanceInteger540000
merchantFrozenAmountFrozen AmountInteger40000
canUseAmountAvailable AmountInteger500000
settlementListSettlement ListLIST
- settlementDateSettlement DateString2020-12-28
- settlementAmountSettlement AmountInteger44500

Signature Rule

RSA(merchantCode + timestamp)

Request Example

{
  "merchantCode": "test",
  "timestamp": 1604384758793,
  "sign": "a1b2c3d4e5f6..."
}

Response Example

{
  "code": "000",
  "merchantBlance": 540000,
  "merchantFrozenAmount": 40000,
  "canUseAmount": 500000
}

Async Callback

Payment Callback

After payment is completed, the system will send a POST request to your configured callbackUrl

Callback Parameters

Parameter NameDescriptionTypeExample
codeResponse CodeString000
messageResponse MessageStringcomplete
orderNumberMerchant Order NumberString1604384758793
amountPayment AmountInteger40000
merchantCodeMerchant CodeStringtest
phonePhone (hidden as 00)String00
emailEmail (hidden as 00)String00
userNameUser NameStringJohn Doe
channelCodeChannel CodeStringM1
statusStatus: 0 Pending, 1 SuccessInteger1
createTimeOrder Create Time (timestamp)Long1617695193459
payTimePayment Time (timestamp, returned on success)Long1617695193459
rsaSignRSA signature = RSA(amount + channelCode + email + merchantCode + orderNumber + phone + userName)Stringa1b2c3d4e5f6

Verification: Concatenate the callback fields above in the order shown to rebuild the plaintext string src, then decrypt rsaSign with the platform RSA public key using PKCS#1 v1.5 (type1) (recovering 0x00 0x01 FF..FF 0x00 + src) and compare it byte-by-byte with src. The callback is valid only when they match (same algorithm as request signing, not SHA256withRSA).

Callback Example

{
  "code": "000",
  "message": "complete",
  "orderNumber": "1604384758793",
  "amount": 40000,
  "merchantCode": "test",
  "phone": "00",
  "email": "00",
  "userName": "John Doe",
  "channelCode": "M1",
  "status": 1,
  "createTime": 1617695193459,
  "payTime": 1617695193459,
  "rsaSign": "a1b2c3d4e5f6"
}

Response: Please return HTTP 200 status code to confirm receipt of callback

Disbursement Callback

After disbursement is completed, the system will send a POST request to your configured callbackUrl

Callback Parameters

Parameter NameDescriptionTypeExample
codeResponse CodeString000
messageResponse MessageStringcomplete
orderNumberMerchant Order NumberString1604384758793
amountDisbursement AmountInteger40000
merchantCodeMerchant CodeStringtest
phonePhone (hidden as 00)String00
emailEmail (hidden as 00)String00
userNameRecipient NameStringJohn Doe
bankCodeBank CodeStringPERMATA
bankAccountBank AccountString100100100
channelCodeChannel CodeStringM1
statusStatus: 1 Success, 2 FailedInteger1
createTimeOrder Create Time (timestamp)Long1617695193459
payTimePayment Time (timestamp, returned on success)Long1617695193459
rsaSignRSA signature = RSA(amount + bankAccount + bankCode + channelCode + email + merchantCode + orderNumber + phone + userName)Stringa1b2c3d4e5f6

Verification: Concatenate the callback fields above in the order shown to rebuild the plaintext string src, then decrypt rsaSign with the platform RSA public key using PKCS#1 v1.5 (type1) (recovering 0x00 0x01 FF..FF 0x00 + src) and compare it byte-by-byte with src. The callback is valid only when they match (same algorithm as request signing, not SHA256withRSA).

Callback Example

{
  "code": "000",
  "message": "complete",
  "orderNumber": "1604384758793",
  "amount": 40000,
  "merchantCode": "test",
  "phone": "00",
  "email": "00",
  "userName": "John Doe",
  "bankCode": "PERMATA",
  "bankAccount": "100100100",
  "channelCode": "M1",
  "status": 1,
  "createTime": 1617695193459,
  "payTime": 1617695193459,
  "rsaSign": "a1b2c3d4e5f6"
}

Response: Please return HTTP 200 status code to confirm receipt of callback

Payment Channel Code Reference

🇮🇩 Indonesia
channel_codechannel_nameType
QRISQRISCollection
VCCredit Card (Visa / Master)Collection
BKBCA KlikPayCollection
BCABCA Virtual AccountCollection
BBCBCA BCCollection
M1Mandiri Virtual AccountCollection
MEMandiri eCashCollection
MPMandiri PCCollection
BTPermata Bank Virtual AccountCollection
PNPermata NetCollection
A1ATM BersamaCollection
B1CIMB Niaga Virtual AccountCollection
I1BNI Virtual AccountCollection
VAMaybank Virtual AccountCollection
M2UMaybank2UCollection
FTRitelCollection
OVOVOCollection
LALINKAJACollection
DANADANACollection
SPShopee PayCollection
SAShopee Pay AppsCollection
AGBank Artha GrahaCollection
S1Sahabat SampoernaCollection
NIBank Negara IndonesiaCollection
RIBank Rakyat IndonesiaCollection
RIEBRI ePayCollection
ININDOMARETCollection
ALALFAMARTCollection
DOBDanamon Online BankingCollection
DVADanamon Virtual AccountCollection
AIAlto iDebitCollection
JIBJenius IBCollection
JAJAKONECollection
OCOcto ClicksCollection
SKSakukuCollection
ALFAlfagroupCollection
KRKredivoCollection
BLBTNONLINECollection
SVASinarmas Virtual AccountCollection
CASHCashier PaymentCollection
ALLIndonesia Disbursement All ChannelDisbursement
🇵🇰 Pakistan
channel_codechannel_nameType
PK_JAZZJAZZ WalletCollection
PK_EASYEASY WalletCollection
PK_ALLPakistan Disbursement All ChannelDisbursement
🇧🇷 Brazil
channel_codechannel_nameType
BR_BRLQR Code PaymentCollection
BR_ALLPIX Disbursement ChannelDisbursement
🇹🇭 Thailand
channel_codechannel_nameType
TH_QRThailand QR Code PaymentCollection
TH_ALLThailand Disbursement ChannelDisbursement

Bank Code Reference

Disbursement Bank Code List

🇮🇩 Indonesia

bank_codebank_nameactivate
ACEHBPD ACEH✓
AGRISBank Agris
ARTOSBank Artos Indonesia
BANK_NOBUBank Nobu✓
BANK_SUBPD SULAWESI TENGAH✓
BCABank BCA✓
BCASYRBANK BCA SYARIAH✓
BJBBank BJB✓
BJB_SYRBank BJB Syariah✓
BNIBANK BNI✓
BNI_SYRBank BNI Syariah✓
BRIBank BRI✓
BRI_SYRBANK BRI SYARIAH✓
BTNBank BTN✓
BTPNBank BTPN✓
BUKOPINBank Bukopin✓
BUKOPIN_SYRBank Syariah Bukopin✓
BUMI_ARTABank Bumi Arta✓
CHINATRUSTBank Chinatrust Indonesia✓
CIMBBANK CIMB NIAGA✓
COMMONWEALTHBank Commonwealth✓
DANAMONBank Danamon✓
DBSBank DBS Indonesia✓
DINAR_INDONESIABank Dinar Indonesia
DKIBank DKI✓
GANESHABank Ganesha✓
HARDA_INTERNASIONALBank Harda Internasional
ICBCBank ICBC Indonesia✓
INDEX_SELINDOBank Index Selindo✓
INDIABank of India Indonesia✓
JASA_JAKARTABank Jasa Jakarta✓
KESEJAHTERAAN_EKONOMBank Kesejahteraan Ekonomi
MANDIRIBank Mandiri✓
MANDIRI_SYRBank Syariah Mandiri✓
MASPIONBank Maspion Indonesia✓
MAYBANKBANK MAYBANK INDONESIA✓
MAYORABank Mayora✓
MEGABank Mega✓
MUAMALATBank Muamalat Indonesia✓
NATIONALNOBBANK NATIONALNOBU✓
OCBCBank OCBC NISP✓
PANINBank Panin✓
PERMATABank Permata✓
SAHABAT_SAMPOERNABank Sahabat Sampoerna✓
SINARMASBank Sinarmas✓
STANDARD_CHARTEREDStandard Chartered Bank✓
SULUTBANK SULUT✓
UOBBank UOB Indonesia✓
VICTORIA_SYRBank Victoria Syariah✓
CITIBANKCitibank✓
ARTHABank Artha Graha Internasional✓
TOKYOBank of Tokyo Mitsubishi UFJ✓
CAPITALBank Capital Indonesia✓
ANZANZ Indonesia✓
BOCBank of China (Hong Kong) Limited✓
HSBCHSBC Indonesia✓
RABOBANKRabobank International Indonesia✓
MAYAPADABank Mayapada✓
DAERAH_ISTIMEWABPD DIY✓
JAWATIMURBPD JAWA TIMUR/SYARIAH✓
JAMBIBank Jambi✓
SUMUTBank Sumut✓
SUMATERA_BARATBPD SUMATERA BARAT/NAGARI SYARIAH✓
RIAU_DAN_KEPRIBank Riau Kepri✓
SUMSEL_DAN_BABELBank Sumsel Babel✓
LAMPUNGBank Lampung✓
KALIMANTAN_SELATANBPD KALIMANTAN SELATAN✓
KALIMANTAN_TIMURBPD KALIMANTAN TIMUR DAN KALIMANTAN UTARA✓
KALIMANTAN_TENGAHBPD KALIMANTAN TENGAH✓
SULSELBARBank Sulselbar✓
NUSA_TENGGARA_BARATBPD NUSA TENGGARA BARAT SYARIAH✓
BALIBPD Bali✓
NUSA_TENGGARA_TIMURBPD NUSA TENGGARA TIMUR✓
MALUKUBank Maluku✓
PAPUABank Papua✓
BENGKULUBank Bengkulu✓
SULAWESIBank Sulteng✓
NUSANTARAPARAHYANGABank Nusantara Parahyangan
MESTIKADHARMABank Mestika Dharma✓
QNBKESAWANQNB Indonesia✓
WOORIBank Woori Saudara✓
BTPNSYRBank BTPN Syariah✓
HANAKEB Hana Bank Indonesia✓
MNC_INTERNASIONALBank MNC Internasional✓
AGRONIAGAAGRONIAGA✓
SBIINDONESIASBI Indonesia✓
ROYALBank Royal Indonesia✓
MEGASYRBank Mega Syariah✓
INAPERDANABank Ina Perdana✓
VICTORIAINTERNASIONBank Victoria International✓
BANTENBPD Banten✓
MUTIARABank Mutiara
PANINSYRPanin Dubai Syariah✓
ANTARDAERAHBank Antardaerah
CCBBank China Construction Bank Indonesia✓
CNBBank CNB (Centratama Nasional Bank)✓
EKABPR EKA (Bank Eka)✓
MANTAPBANK MANTAP (Mandiri Taspen)✓
MASBank Multi Arta Sentosa (Bank MAS)✓
PRIMABank Prima Master✓
SHINHANBank Shinhan Indonesia✓
YUDHA_BAKTIBank Yudha Bakti
GOPAYGoPay✓
OVOOVO✓
SHOPEEPAYShopeePay✓
DANADana✓
LINKAJALinkAja
KALIMANTANBARATBPD Kalimantan Barat Bank Kalbar✓
JAWATENGAHBPD JAWA TENGAH✓
ALTOALTO
BSIBSI (Bank Syariah Indonesia)✓
AMARBANK AMAR INDONESIA✓
CTBCBANK CTBC INDONESIA✓
IBKBANK IBK INDONESIA✓
BRA_CPFBRA CPF✓
BNEOBANK NEO COMMERCE
BSEAIBANK SEABANK INDONESIA✓
BJAGOBANK JAGO
ALADINBANK ALADIN SYARIAH
BACBANK API CHANNEL

🇵🇰 Pakistan

bank_codebank_name
PK_EASYEASY Wallet
PK_JAZZJAZZ Wallet

🇧🇷 Brazil

bank_codebank_name
BR_CPFCPF Number
BR_PHONEPhone Number
BR_EMAILEmail

🇹🇭 Thailand

bank_codebank_name
TH_BAACBANK FOR AGRICULTURE AND AGRICULTURAL COOPERATIVES
TH_BAYBANK OF AYUDHYA PUBLIC COMPANY LIMITED
TH_BBLBANGKOK BANK PUBLIC COMPANY LTD.
TH_CIMBTCIMB THAI BANK PUPBLIC COMPANY LTD.
TH_CITICITIBANK, N.A.
TH_GHBTHE GOVERNMENT HOUSING BANK
TH_GSBTHE GOVERNMENT SAVINGS BANK
TH_ISBTISLAMIC BANK OF THAILAND
TH_ICBCTINDUSTRIAL AND COMMERCIAL BANK OF CHINA (THAI) PUBLIC COMPANY LIMITED
TH_KBANKKASIKORNBANK PUBLIC COMPANY LTD.
TH_KKKIATNAKIN BANK PUBLIC COMPANY LIMITED
TH_KTBKRUNG THAI BANK PUBLIC COMPANY LTD.
TH_LHBANKLAND AND HOUSES BANK PUBLIC COMPANY LIMITED
TH_MIZUHOMIZUHO CORPORATE BANK, LTD.
TH_SCBSIAM COMMERCIAL BANK PUBLIC COMPANY LTD
TH_SCBTSTANDARD CHARTERED BANK (THAI) PUBLIC COMPANY LIMITED
TH_SMBCSUMITOMO MITSUI BANKING CORPORATION
TH_TBANKTHANACHART BANK PUBLIC COMPANY LTD.
TH_TCRTHE THAI CREDIT RETAIL BANK PUBLIC COMPANY LIMITED
TH_TISCOTISCO BANK PUBLIC COMPANY LIMITED
TH_TMBTMB BANK PUBLIC COMPANY LIMITED
TH_TTBTMBTHANACHART BANK PUBLIC COMPANY LIMITED
TH_UOBTUNITED OVERSEAS BANK (THAI) PUBLIC COMPANY LIMITED
TH_PROMPTPAYPromptPay