API Documentationeer
Overview
This document will guide you step by step to implement our API service. Here is the API flow with its example.
You may need to refer to these environment URLs:
Sandbox: For testing and integration. No real money is involved.
Production: For live transactions with real customers.
You can have a look at the general sequence diagram.
API Key
Step 1: Add API Key to Request Header
You will need to add API Key field to Header of every Requests as following:
"x-api-key": "api_key"User Registeration flow
With this flow follow User path
Step 1: User Register
You will need to make a POST request to /api/v1/user/register
POST /api/v1/user/register
Resquest
{
email: "[email protected]",(Optional)
walletAddress: "abcd...feg234"
}
Response
{
status: "success",
message: "User registered successfully",
user: { id: 18, email: "[email protected]" }
}Step 2: User KYC
User need to be KYC-ed to be able to make a payment. You will need to make a POST request to /api/v1/kyc/link
POST /api/v1/kyc/link
Request
{
email: "[email protected]", (Optional)
walletAddress: "wallet_address_string"
}
Response
{
success: true ,
message: "KYC external link generated successfully",
websdkUrl: "<https://linktokyc/websdk/p/example.com>",
}Payment Flow
With this flow follow Payment path
Step 1: Place Order
You will need to make a POST request to /api/v1/placeOrder
⚠️ Please be caution:
These QR string was meant to be use in SANDBOX.
DO NOT USE IT IN PRODUCTION
To test with VND please use this QR String:
qrString: "00020101021138560010A0000007270126000697040701128888123456780208QRIBFTTA53037045802VN63042249"To test with PHP please use this QR String:
qrString: "00020101021127590012com.p2pqrpay0111UBPHPHMMXXX02089996440304121096459500755204601653036085802PH5925Sophia Marie Chavez Dever6009SAN PEDRO63043708"POST /api/v1/placeOrder
Request
{
qrString: "qrString",
amount: 51000, #Please test with the amount higher than 50,000 VND or 10 PHP
fiatCurrency: "VND",
cryptoCurrency: "USDC",
chain: "Solana",
fromAddress: "fromWalletAddress"
}
Response
{
orderId: "order_id_string",
status: "awating_crypto_transfer",
qrString: "qrString",
fiatAmount: 20000,
fiatCurrency: "VND",
cryptoAmount: 0.8,
cryptoCurrency: "USDC",
exchangeRate: 26000,
qrInfo: {
encodedString: "qrString",
providerInfo: {
name: "VIETQR",
guid: "A000000727",
service: "QRIBFTTA"
},
bankInfo: {
bankBin: "123456",
bankNumber: "567891"
},
amount: 0,
additionalData: "GaianWithLove"
},
cryptoTransferInfo: {
chain: "Solana",
fromAddress: "fromWalletAddress",
toAddress: "toWalletAddress",
token: "USDCAddress",
amount: 800000,
encodedTransaction: "encodedTransactionInstruction",
amountInDecimal: 0.8,
feeInfo: {
feeToken: "feeTokenAddress",
feeAmount: "feeAmount",
feeAmountInDecimal: "feeAmountInDecimal"
}
},
timestamp: "timeStamp"
}Step 2: Build and Sign the Transaction
This will need to be perform on your side. You will need a build instruction function, example in TypeScript:
decodeTransaction = async (
data: PlaceOrderResponse
): Promise<Transaction> => {
if (!this.solanaConnection)
throw new Error(Solana connection not defined);
const { blockhash } = await this.solanaConnection.getLatestBlockhash(
confirmed
);
const transferInstruction = await buildSolanaSendTransactionInstruction(
new PublicKey(data.cryptoTransferInfo.fromAddress),
new PublicKey(data.cryptoTransferInfo.toAddress),
new PublicKey(data.cryptoTransferInfo.token),
data.cryptoTransferInfo.amount
);
// Create Legacy Transaction instead of VersionedTransaction
const transaction = new Transaction();
transaction.add(transferInstruction);
transaction.recentBlockhash = blockhash;
transaction.feePayer = new PublicKey(data.cryptoTransferInfo.fromAddress);
return transaction;
};Then sign and submit the transaction to chain.
Step 3: Verify Order
After submitting the transaction to chain, you will need to make a POST request with the transaction hash (tx_Hash) hash and order Id ( order_id_string), to /api/v1/verifyOrder
POST /api/v1/verifyOrder
Request
{
orderId: "order_id_string",
transactionProof: "tx_Hash"
}
Response
{
orderId: "order_id_string",
status: "verified" , #List of status: awaiting_crypto_transfer, verified, processing, failed or completed
transactionHash: "tx_Hash",
message: "Transaction verified and bank transfer queued",
bankTransferStatus: "queued"
}Step 4: Polling the Status
After the order is verified , it will be auto-processing. Then you will need to make a polling function to make a GET request to /api/v1/status after an amount of time
GET /api/v1/status
Request
{
orderId: "order_id_string"
}
Response (Processing)
{
id: 138,
orderId: "order_id_string",
status: "processing",
fiatAmount: 20000,
fiatCurrency: "VND",
cryptoAmount: 0.8,
cryptoCurrency: USDC,
exchangeRate: 26000,
qrInfo: {
bankInfo: {
bankBin: "123456",
bankNumber: "567891"
},
providerInfo: {
guid: "A000000727",
name: "VIETQR",
service: "QRIBFTTA"
},
encodedString: "qrString"
},
paymentMethod: "qr_code",
expiresAt: "timeStamp",
bankTransactionReference: {},
createdAt: "timeStamp",
updatedAt: "timeStamp",
userId: null,
transactionHash: "tx_Hash",
pollCount: 24,
lastChecked: "time"
}
Response (Completed)
{
id: 138,
orderId: "order_id_string",
status: "completed",
fiatAmount: 20000,
fiatCurrency: "VND",
cryptoAmount: 0.8,
cryptoCurrency: USDC,
exchangeRate: 26000,
qrInfo: {
bankInfo: {
bankBin: "123456",
bankNumber: "567891"
},
providerInfo: {
guid: "A000000727",
name: "VIETQR",
service: "QRIBFTTA"
},
encodedString: "qrString"
},
paymentMethod: "qr_code",
expiresAt: "timeStamp",
bankTransactionReference: {
requestId: "require_id",
requestDate "timeStamp"
},
createdAt: "timeStamp",
updatedAt: "timeStamp",
userId: null,
transactionHash: "tx_Hash",
pollCount: 24,
lastChecked: "time"
}Additional API
Parse QR API
With this flow follow Payment path
You will need to make a POST request to /api/v1/parseQr
POST /api/v1/parseQr
Request
{
qrString: "Qr_string",
country: "VN"
}
Response
{
success: true ,
qrInfo: {
isValid: true ,
encodedString: "Qr_string",
country: "VN",
qrProvider: "VIETQR",
bankBin: "123456",
accountNumber: "567891",
currency: "704",
nation: "VN",
beneficiaryName: "NGUYEN VAN A",
detailedQrInfo: {
provider: {
fieldId: "38",
guid: "A000000727",
name: "VIETQR",
data: "data_string",
service: "QRIBFTTA"
},
consumer: {
bankBin: "123456",
bankNumber: "567891",
},
merchant: {
},
additionalData: {
},
version: "01",
initMethod: "11",
currency: "704",
nation: "VN",
crc: "60C4"
}
},
}Calculate Exchange
With this flow follow Payment path
Calculate cryptocurrency equivalent for fiat amount with current exchange rates
You will need to make a POST request to /api/v1/calculateExchange
POST /api/v1/calculateExchange
Request
{
amount: 26000,
country: "VN",
chain: "Solana",
token: "USDC"
}
Response
{
success: true,
exchangeInfo: {
fiatAmount: 26000,
fiatCurrency: "VND",
cryptoAmount: "0.9846",
cryptoCurrency: "USDC",
exchangeRate: "26407.63793324218",
chain: "Solana",
token: "USDC",
timestamp: "timeStamp",
feeAmount: "fee_Amount"
}
}Get Transaction History
With this flow follow User path
By User Email
You will need to make a GET request to /api/v1/users/{User_Email}/orders
GET /api/v1/users/{User_Email}/orders
Request
{
page: 1, (Optional)
limit: 5, (Optional)
status: "completed" (Optional)
}
Response
{
status: "success",
data: {
user: {
id: 12,
email: "User_Email",
walletAddress: "Wallet_Address",
createdAt: "2025-09-15T04:28:20.451Z",
updatedAt: "2025-09-15T05:33:57.873Z"
},
orders: {
items: [], #Empty because there are no complete order
pagination: {
page: 1,
limit: 5,
total: 0,
totalPages: 0,
hasNext: false,
hasPrev: false
}
}
}
}By User Wallet
You will need to make a GET request to /api/v1/users/wallet/{User_Wallet}/orders
GET /api/v1/users/wallet/{User_Wallet}/orders
Request
{
page: 1, (Optional)
limit: 5, (Optional)
status: "completed" (Optional)
}
Response
{
status: "success",
data: {
user: {
id: 12,
email: "User_Email",
walletAddress: "Wallet_Address",
createdAt: "2025-09-15T04:28:20.451Z",
updatedAt: "2025-09-15T05:33:57.873Z"
},
orders: {
items: [], #Empty because there are no complete order
pagination: {
page: 1,
limit: 5,
total: 0,
totalPages: 0,
hasNext: false,
hasPrev: false
}
}
}
}Get User Infomation
With this flow follow User path
By User Email or User Wallet Address
You will need to make a GET request to /api/v1/users/?email="?"
Or, you will need to make a GET request to /api/v1/users/?walletAddress="?"
GET /api/v1/users/?email="[email protected]"
Request
{
<email:"[email protected]>"
}
Response
{
"status": "success",
"user": {
"id": 1,
"email": "[email protected]",
"walletAddress": "abdcefghijklmnopqrstuvwxyz",
"kyc": {
"status": "approved", //Status gonna have:[not started, under review, approved, rejected]
"firstName": "John",
"lastName": "Mock-Doe",
"country": "VNM",
"applicantPlatform": "Web",
"phone": null
}
}
}
GET /api/v1/users/?walletAddress="abdcefghijklmnopqrstuvwxyz"
Request
{
walletAddress:"abdcefghijklmnopqrstuvwxyz"
}
Response
{
"status": "success",
"user": {
"id": 1,
"email": "[email protected]",
"walletAddress": "abdcefghijklmnopqrstuvwxyz",
"kyc": {
"status": "approved",
"firstName": "John",
"lastName": "Mock-Doe",
"country": "VNM",
"applicantPlatform": "Web",
"phone": null
}
}
}API Reference
KYC Requirement
Last updated