curl --request GET \
--url https://api.rach.finance/api/v1/wallet/{customerID}/balances \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.rach.finance/api/v1/wallet/{customerID}/balances"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.rach.finance/api/v1/wallet/{customerID}/balances', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.rach.finance/api/v1/wallet/{customerID}/balances",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.rach.finance/api/v1/wallet/{customerID}/balances"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.rach.finance/api/v1/wallet/{customerID}/balances")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rach.finance/api/v1/wallet/{customerID}/balances")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"customer_id": "<string>",
"addresses": [
{
"network": "ETH",
"address": "<string>",
"index": 123,
"source": "database",
"balances": [
{
"currency": "USDT",
"balance": "125.50",
"spendable": "125.50",
"confirmed": "0.04",
"as_of": "2023-11-07T05:31:56Z",
"note": "<string>"
}
]
}
],
"total": 123,
"note": "<string>",
"refresh_requested": true,
"refresh_eta_seconds": 30
}Balances for a customer wallet
Returns balances for every derived address of the customer wallet — native coin plus supported stablecoins (USDT/USDC where applicable).
Served from Rach’s database, not a live chain read. The deposit monitor keeps the stored figure in step with the chain, raising it on deposits and lowering it on spends, so this endpoint costs nothing and can be polled as often as your UI needs.
| Query | Behaviour |
|---|---|
| (none) | Stored balances, returned immediately. |
?refresh=true | Returns stored balances immediately and schedules the monitor to re-read these addresses on its next cycle (typically ≤30s). Responds with refresh_requested: true and refresh_eta_seconds; poll again after that interval. Concurrent refresh requests collapse into one chain read. |
?live=true | Reads the chain directly, throttled per address. Needed only for the confirmed-vs-unconfirmed split on BTC/LTC/BCH, or when auditing for drift. |
Each address object carries source (database or chain) and an array of per-currency
balances; every supported currency for the network is present, including zeros. Each
balance carries as_of — when that figure was last read from the chain.
spendable is what can actually be sent right now:
- XRP: excludes the locked ~1 XRP base reserve.
- BTC / LTC / BCH: with
?live=true,confirmedcounts confirmed UTXOs only;balancemay include unconfirmed (0-conf) funds. - All other networks:
spendableequalsbalance.
curl --request GET \
--url https://api.rach.finance/api/v1/wallet/{customerID}/balances \
--header 'X-API-Key: <api-key>'import requests
url = "https://api.rach.finance/api/v1/wallet/{customerID}/balances"
headers = {"X-API-Key": "<api-key>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {'X-API-Key': '<api-key>'}};
fetch('https://api.rach.finance/api/v1/wallet/{customerID}/balances', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.rach.finance/api/v1/wallet/{customerID}/balances",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.rach.finance/api/v1/wallet/{customerID}/balances"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("X-API-Key", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.rach.finance/api/v1/wallet/{customerID}/balances")
.header("X-API-Key", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.rach.finance/api/v1/wallet/{customerID}/balances")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["X-API-Key"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"customer_id": "<string>",
"addresses": [
{
"network": "ETH",
"address": "<string>",
"index": 123,
"source": "database",
"balances": [
{
"currency": "USDT",
"balance": "125.50",
"spendable": "125.50",
"confirmed": "0.04",
"as_of": "2023-11-07T05:31:56Z",
"note": "<string>"
}
]
}
],
"total": 123,
"note": "<string>",
"refresh_requested": true,
"refresh_eta_seconds": 30
}Authorizations
Business API key for server-to-server integrations.
Key prefix determines the environment — no separate flag needed:
test_sk_* = sandbox/testnet, live_sk_* = production/mainnet.
Path Parameters
Query Parameters
Schedule a monitor re-read of these addresses on its next cycle and return stored balances immediately. Does NOT block on a chain read.
Read the chain directly instead of the stored figure. Throttled per address; use only when you need the confirmed/unconfirmed split or are auditing for drift.
Response
Balances per address
Show child attributes
Show child attributes
Explains the database-backed behaviour and the refresh/live options.
Present only when ?refresh=true or ?live=true was passed.
true
Roughly how long until a requested refresh is reflected. Poll again after this interval.
30

