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.
Payment: https://payments.gaian-dev.network
You can have a look at the general sequence diagram.
API Key
Step 1: Add API Key to RequestAdd th
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]",
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]",
}
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
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
}
}
}
}API Reference
Last updated