@gaian-network/sdk
v0.1.0
Published
TypeScript SDK for the Gaian Network API — cross-border crypto-to-fiat payments
Maintainers
Readme
@gaian-network/sdk
TypeScript SDK for the Gaian Network API — cross-border crypto-to-fiat payments.
Features
- Full TypeScript types for all requests and responses
- Two payment flows: standard (on-chain signing) and prefunded (no signing required)
- KYC verification link generation and direct submission
- QR code parsing for VN / PH / BR payment QRs
- Exchange rate calculation
- Tenant balance and policy checks
- Zero runtime dependencies — uses native
fetch(Node ≥ 18)
Installation
npm install @gaian-network/sdkQuick start
import { GaianClient } from '@gaian-network/sdk';
const client = new GaianClient({
apiKey: process.env.GAIAN_API_KEY!,
environment: 'sandbox', // or 'production'
});Get your API key at client-admin.gaian.network.
API reference
new GaianClient(options)
| Option | Type | Required | Default |
|--------|------|----------|---------|
| apiKey | string | Yes | — |
| environment | 'sandbox' \| 'production' | No | 'sandbox' |
| baseUrls.user | string | No | env default |
| baseUrls.payment | string | No | env default |
| timeoutMs | number | No | 30000 |
client.users
register(params)
Register a new user. Returns the existing user if the wallet address is already registered.
const { user } = await client.users.register({
walletAddress: 'So11111111111111111111111111111111111111112',
});
// user.id, user.walletAddress, user.createdAtgetById(id)
const { data: user } = await client.users.getById(123);
// user.kycStatus, user.firstName, user.kyc.markets, ...getByWallet(walletAddress)
const { data: user } = await client.users.getByWallet('So111...');getMarkets(walletAddress)
Get per-market KYC approval status.
const { data } = await client.users.getMarkets('So111...');
// data.markets.VN.status, data.markets.PH.status, ...getOrdersByIdentifier(identifier, params?)
Paginated order history by user ID or email.
const { data } = await client.users.getOrdersByIdentifier('[email protected]', {
page: 1,
limit: 20,
status: 'completed',
});
// data.orders.items, data.orders.paginationgetOrdersByWallet(walletAddress, params?)
const { data } = await client.users.getOrdersByWallet('So111...', { page: 1 });client.kyc
generateLink(params)
Generate a time-limited KYC verification link (Sumsub). Redirect the user to websdkUrl.
const { websdkUrl } = await client.kyc.generateLink({
walletAddress: 'So111...',
});
window.location.href = websdkUrl; // redirect userDo not cache
websdkUrl— generate a fresh link each time.
submit(params)
Submit KYC data directly when you have already collected identity documents.
const result = await client.kyc.submit({
userWalletAddress: 'So111...',
userEmail: '[email protected]',
firstName: 'Nguyen',
lastName: 'Van A',
dateOfBirth: '1990-01-15',
gender: 'male',
nationality: 'VN',
type: 'ID_CARD',
nationalId: '012345678901',
issueDate: '2015-01-01',
expiryDate: '2025-01-01',
addressLine1: '123 Le Loi',
addressLine2: 'Quan 1',
city: 'Ho Chi Minh',
state: 'Ho Chi Minh',
zipCode: '700000',
// base64 data URLs: data:image/jpeg;base64,...
frontIdImage: 'data:image/jpeg;base64,...',
backIdImage: 'data:image/jpeg;base64,...',
holdIdImage: 'data:image/jpeg;base64,...',
phoneNumber: '0901234567',
phoneCountryCode: '+84',
});Max request body size is 10 MB. Supported image formats:
jpeg,png,gif,webp.
client.payments
placeOrder(params) — Standard flow
Place an order using an on-chain transaction.
const order = await client.payments.placeOrder({
qrString: '00020101021238570010A0000007...',
amount: 500000, // fiat amount (VND)
cryptoCurrency: 'USDC',
fromAddress: 'So111...',
chain: 'Solana', // optional, defaults to Solana
fiatCurrency: 'VND', // optional, auto-detected from QR
});
// order.orderId, order.cryptoTransferInfo, order.cryptoAmountAfter calling placeOrder, use order.cryptoTransferInfo to build and sign a legacy Solana transaction (not VersionedTransaction), then call verifyOrder.
placeOrderPrefund(params) — Prefunded flow
Deduct from tenant's pre-loaded balance. No on-chain signing required.
const order = await client.payments.placeOrderPrefund({
qrString: '00020101021238570010A0000007...',
amount: 500000,
cryptoCurrency: 'USDC',
fromAddress: 'So111...',
});
// proceed directly to pollingverifyOrder(params)
Submit the transaction hash after broadcasting the on-chain transaction.
const result = await client.payments.verifyOrder({
orderId: order.orderId,
transactionProof: 'txSignatureOrHash...', // 66–100 chars
});
// result.status: 'verified' | 'failed' | 'pending'
// result.bankTransferStatus: 'queued' | 'failed'getOrderStatus(orderId)
Poll until status is 'completed' or 'failed'.
const status = await client.payments.getOrderStatus(order.orderId);
// status.status, status.fiatAmount, status.transactionHash, ...client.exchange
calculate(params)
Get the crypto equivalent for a fiat amount before placing an order.
const { exchangeInfo } = await client.exchange.calculate({
amount: 500000,
country: 'VN',
chain: 'Solana',
token: 'USDC',
});
// exchangeInfo.cryptoAmount, exchangeInfo.exchangeRate, exchangeInfo.feeAmountclient.qr
parse(params)
Parse a merchant QR string and extract payment details.
const { qrInfo } = await client.qr.parse({
qrString: '00020101021238570010A0000007...',
country: 'VN', // optional hint
});
// qrInfo.isValid, qrInfo.bankBin, qrInfo.accountNumber, qrInfo.beneficiaryNameclient.tenant
getBalance(currency?)
const balance = await client.tenant.getBalance('USDC');
// balance.availableBalance, balance.walletAddress, balance.chaingetTotalSpent()
const { totalSpent, limit } = await client.tenant.getTotalSpent();checkPolicy(params)
Check if a wallet is allowed to transact in a given country.
const policy = await client.tenant.checkPolicy({
walletAddress: 'So111...',
countryCode: 'VN',
});
// policy.isAllowed, policy.tier ('KYC' | 'NON_KYC'), policy.limits.perTransactionPayment flows
Standard payment (end-to-end)
import { GaianClient, GaianError } from '@gaian-network/sdk';
const client = new GaianClient({ apiKey: process.env.GAIAN_API_KEY! });
async function pay(walletAddress: string, qrString: string) {
// 1. Check KYC
const policy = await client.tenant.checkPolicy({ walletAddress, countryCode: 'VN' });
if (!policy.isAllowed) throw new Error(policy.reason ?? 'Payment not allowed');
// 2. Place order
const order = await client.payments.placeOrder({
qrString,
amount: 500_000,
cryptoCurrency: 'USDC',
fromAddress: walletAddress,
chain: 'Solana',
});
// 3. Build + sign + broadcast transaction using order.cryptoTransferInfo
const txSignature = await signAndSendTransaction(order.cryptoTransferInfo);
// 4. Verify
await client.payments.verifyOrder({
orderId: order.orderId,
transactionProof: txSignature,
});
// 5. Poll until complete
return pollOrderStatus(client, order.orderId);
}
async function pollOrderStatus(client: GaianClient, orderId: string) {
while (true) {
const status = await client.payments.getOrderStatus(orderId);
if (status.status === 'completed' || status.status === 'failed') return status;
await new Promise(r => setTimeout(r, 3_000));
}
}Prefunded payment
const order = await client.payments.placeOrderPrefund({
qrString,
amount: 500_000,
cryptoCurrency: 'USDC',
fromAddress: walletAddress,
});
// No verifyOrder needed — go straight to polling
const final = await pollOrderStatus(client, order.orderId);KYC flow
// Check market status first
const { data } = await client.users.getMarkets(walletAddress);
const vnStatus = data.markets['VN']?.status;
if (vnStatus !== 'approved') {
// Generate a fresh KYC link and redirect
const { websdkUrl } = await client.kyc.generateLink({ walletAddress });
window.location.href = websdkUrl;
}Error handling
All errors thrown are instances of GaianError:
import { GaianError } from '@gaian-network/sdk';
try {
await client.users.getById(999);
} catch (err) {
if (err instanceof GaianError) {
console.log(err.code); // 'NOT_FOUND' | 'UNAUTHORIZED' | 'BAD_REQUEST' | ...
console.log(err.statusCode); // 404
console.log(err.message); // API error message
console.log(err.details); // raw response body
}
}| code | HTTP status | When |
|--------|------------|------|
| UNAUTHORIZED | 401 | Missing or invalid API key |
| FORBIDDEN | 403 | Valid key, insufficient permissions |
| NOT_FOUND | 404 | User or order does not exist |
| BAD_REQUEST | 400 | Invalid request parameters |
| CONFLICT | 409 | Resource already exists (user registration) |
| SERVER_ERROR | 5xx | Gaian server error — retry with backoff |
| NETWORK_ERROR | — | Network timeout or connection failure |
Environments
| Environment | User API | Payment API |
|-------------|----------|-------------|
| sandbox | https://dev-user.gaian-dev.network | https://dev-payments.gaian-dev.network |
| production | https://user.gaian-dev.network | https://payments.gaian-dev.network |
Override base URLs for testing or proxying:
const client = new GaianClient({
apiKey: 'test-key',
baseUrls: {
user: 'http://localhost:3001',
payment: 'http://localhost:3002',
},
});Requirements
- Node.js ≥ 18 (native
fetch) - TypeScript ≥ 5.0 (for
exactOptionalPropertyTypes)
License
MIT
