API reference
Balances
Read a customer's spendable balance, adjust it, and check your app pool.
Customer balance
Returns the customer's spendable balance per asset. It grows automatically when the customer deposits, and you raise or lower it with balance/adjust.
GET
/api/partner/{app_id}/users/{user_id}/balance/Get a customer's balance.
Path parameters
app_idstringrequiredYour app ID (UUID), shown on the app's Developer tab.user_idstringrequiredYour customer ID — the user_id you created the customer with.
Request example
curl "https://api.moallet.com/api/partner/{app_id}/users/{user_id}/balance/" \
-H "Authorization: ApiKey {client_id}:{client_secret}"200 OK
{
"success": true,
"data": [
{
"asset": {
"id": 2,
"symbol": "USDT",
"network": "Solana Mainnet"
},
"spendable_amount": "150.000000000000000000"
},
{
"asset": {
"id": 1,
"symbol": "SOL",
"network": "Solana Mainnet"
},
"spendable_amount": "0.500000000000000000"
}
],
"error": null
}Customer balance object
assetobjectAsset: id, symbol and network.spendable_amountstringSpendable balance — your ledger of what the customer can use.
Adjust a customer balance
Increase (CREDIT) or decrease (DEBIT) a customer's spendable balance — for example after the customer spends inside your product, or after you pay them out. A DEBIT larger than the balance is rejected. Send an idempotency_key so that a retry is applied only once.
POST
/api/partner/{app_id}/users/{user_id}/balance/adjust/Adjust a customer's balance.
Path parameters
app_idstringrequiredYour app ID (UUID), shown on the app's Developer tab.user_idstringrequiredYour customer ID — the user_id you created the customer with.
Body parameters
amountdecimal stringrequiredAmount to change, as a positive decimal string.directionCREDIT | DEBITrequiredCREDIT (increase) or DEBIT (decrease).asset_idintegerAsset ID. Optional — see GET /api/partner/chains/ for IDs.idempotency_keystringOptional. The same key is applied only once, however often you retry.reasonstringOptional note, stored in the audit ledger.
Request example
curl -X POST "https://api.moallet.com/api/partner/{app_id}/users/{user_id}/balance/adjust/" \
-H "Authorization: ApiKey {client_id}:{client_secret}" \
-H "Content-Type: application/json" \
-d '{
"amount": "50",
"direction": "DEBIT",
"idempotency_key": "spend-2026-10-22-0001",
"reason": "Order 4471"
}'200 OK
{
"success": true,
"data": {
"user_id": "customer-1001",
"asset": {
"id": 2,
"symbol": "USDT"
},
"direction": "DEBIT",
"amount": "50",
"spendable_amount": "100.000000000000000000"
},
"error": null
}Error codes
INSUFFICIENT_SPENDABLE400INSUFFICIENT_SPENDABLE — the DEBIT is larger than the customer's spendable balance.
App pool balance
Returns your app pool per asset: the total, how much is on the 72-hour hold, what you can pay out now, and the network fee for an on-chain payout.
GET
/api/partner/{app_id}/total-balance/Get the app pool balance.
Path parameters
app_idstringrequiredYour app ID (UUID), shown on the app's Developer tab.
Request example
curl "https://api.moallet.com/api/partner/{app_id}/total-balance/" \
-H "Authorization: ApiKey {client_id}:{client_secret}"200 OK
{
"success": true,
"data": [
{
"asset": {
"id": 2,
"symbol": "USDT",
"name": "USDT (SPL)",
"network": "Solana Mainnet"
},
"total_amount": "125000.500000000000000000",
"withdrawal_fee": "1.000000",
"payout_locked": "300.000000000000000000",
"payout_available": "124700.500000000000000000"
},
{
"asset": {
"id": 1,
"symbol": "SOL",
"name": "Solana",
"network": "Solana Mainnet"
},
"total_amount": "12.500000000000000000",
"withdrawal_fee": "0.001",
"payout_locked": "0",
"payout_available": "12.500000000000000000"
}
],
"error": null
}Pool balance object
assetobjectAsset: id, symbol, name and network.total_amountstringEverything in the pool for this asset.withdrawal_feestringNetwork fee for an on-chain payout. Taken from the pool together with the amount.payout_lockedstringThe part of the pool on the 72-hour hold.payout_availablestringWhat you can pay out to external wallets right now (total_amount − payout_locked).
Responses can include extra fields kept for compatibility. Ignore any field that isn't documented here.