Holdings
curl --request GET \
--url https://api.cabalspy.xyz/v1/wallets/holdingsimport requests
url = "https://api.cabalspy.xyz/v1/wallets/holdings"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.cabalspy.xyz/v1/wallets/holdings', 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.cabalspy.xyz/v1/wallets/holdings",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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.cabalspy.xyz/v1/wallets/holdings"
req, _ := http.NewRequest("GET", url, nil)
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.cabalspy.xyz/v1/wallets/holdings")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cabalspy.xyz/v1/wallets/holdings")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"active_holdings": {
"tokens": [
{
"token_address": "native",
"token_name": "Solana",
"symbol": "SOL",
"amount": "12480000000",
"amount_formatted": "12.48",
"decimals": 9,
"verified_contract": true
},
{
"token_address": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
"token_name": "invisibull",
"symbol": "invisibull",
"amount": "22113972037624",
"amount_formatted": "22113972.03",
"decimals": 6,
"verified_contract": false
}
],
"count": 2,
"last_updated": "2026-07-06T11:00:12Z",
"stale": false,
"loading": false
}
},
"meta": {
"request_id": "req_5162c7cf7f87",
"cached": false,
"cache_age_seconds": 0,
"version": "1.0.0",
"timestamp": "2026-07-06T11:01:57Z"
}
}
{
"success": true,
"data": {
"active_holdings": {
"tokens": [],
"count": 0,
"last_updated": null,
"stale": false,
"loading": true
}
},
"meta": {
"request_id": "req_9aa1917e433b",
"cached": false,
"cache_age_seconds": 0,
"version": "1.0.0",
"timestamp": "2026-07-06T11:02:10Z"
}
}
Wallet data
Holdings
Current on-chain token balances of a wallet, read live from the chain via Moralis. Period independent, no cost basis.
GET
/
v1
/
wallets
/
holdings
Holdings
curl --request GET \
--url https://api.cabalspy.xyz/v1/wallets/holdingsimport requests
url = "https://api.cabalspy.xyz/v1/wallets/holdings"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.cabalspy.xyz/v1/wallets/holdings', 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.cabalspy.xyz/v1/wallets/holdings",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$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.cabalspy.xyz/v1/wallets/holdings"
req, _ := http.NewRequest("GET", url, nil)
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.cabalspy.xyz/v1/wallets/holdings")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cabalspy.xyz/v1/wallets/holdings")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"active_holdings": {
"tokens": [
{
"token_address": "native",
"token_name": "Solana",
"symbol": "SOL",
"amount": "12480000000",
"amount_formatted": "12.48",
"decimals": 9,
"verified_contract": true
},
{
"token_address": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
"token_name": "invisibull",
"symbol": "invisibull",
"amount": "22113972037624",
"amount_formatted": "22113972.03",
"decimals": 6,
"verified_contract": false
}
],
"count": 2,
"last_updated": "2026-07-06T11:00:12Z",
"stale": false,
"loading": false
}
},
"meta": {
"request_id": "req_5162c7cf7f87",
"cached": false,
"cache_age_seconds": 0,
"version": "1.0.0",
"timestamp": "2026-07-06T11:01:57Z"
}
}
{
"success": true,
"data": {
"active_holdings": {
"tokens": [],
"count": 0,
"last_updated": null,
"stale": false,
"loading": true
}
},
"meta": {
"request_id": "req_9aa1917e433b",
"cached": false,
"cache_age_seconds": 0,
"version": "1.0.0",
"timestamp": "2026-07-06T11:02:10Z"
}
}
Return a wallet current on-chain token balances, read live from the blockchain through Moralis. Unlike the tracker and leaderboard, which are built from the trades CabalSpy observes, this endpoint reflects what the wallet actually holds on chain right now, including the native coin.
Because it reads raw balances from the chain, it has no cost basis and therefore no PnL. It answers one question only, what does this wallet hold at this moment.
This endpoint is period independent. It may return loading true for a brief moment while the balance cache warms up, in that case simply call it again. The wallet must be tracked by CabalSpy, otherwise you get a wallet not found error.
Query Parameters
string
required
Chain of the wallet. One of solana, bnb, base, eth.
string
required
The wallet address whose balances you want.
string
required
Your API key. Alternatively pass it as an Authorization Bearer header.
Usage Example
curl "https://api.cabalspy.xyz/v1/wallets/holdings?blockchain=solana&address=7j7AA3HZR2zEjwAQEKPFh2qucLY4fqZpB9iodf39w8xW&api_key=YOUR_KEY"
import requests
params = {
"blockchain": "solana",
"address": "7j7AA3HZR2zEjwAQEKPFh2qucLY4fqZpB9iodf39w8xW",
"api_key": "YOUR_KEY",
}
r = requests.get("https://api.cabalspy.xyz/v1/wallets/holdings", params=params)
h = r.json()["data"]["active_holdings"]
if h["loading"]:
print("cache warming, retry")
else:
for t in h["tokens"]:
print(t["symbol"], t["amount_formatted"])
const p = new URLSearchParams({
blockchain: "solana",
address: "7j7AA3HZR2zEjwAQEKPFh2qucLY4fqZpB9iodf39w8xW",
api_key: "YOUR_KEY",
});
const res = await fetch(`https://api.cabalspy.xyz/v1/wallets/holdings?${p}`);
const h = (await res.json()).data.active_holdings;
h.tokens.forEach(t => console.log(t.symbol, t.amount_formatted));
Response
boolean
True on success.
object
Show data
Show data
object
Show active_holdings
Show active_holdings
array
Show token
Show token
string
Token contract or mint address. The native coin uses a pseudo address.
string
Token name (may be empty).
string
Token symbol.
string
Raw balance as a string in the smallest unit.
string
Human readable balance adjusted for decimals.
integer
Token decimals.
boolean
Whether the token contract is verified (EVM chains).
integer
Number of tokens held.
string
ISO timestamp of the last balance refresh (null if unknown).
boolean
Whether the cached balance is considered stale.
boolean
True while the balance cache is still warming up. Call again shortly.
{
"success": true,
"data": {
"active_holdings": {
"tokens": [
{
"token_address": "native",
"token_name": "Solana",
"symbol": "SOL",
"amount": "12480000000",
"amount_formatted": "12.48",
"decimals": 9,
"verified_contract": true
},
{
"token_address": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
"token_name": "invisibull",
"symbol": "invisibull",
"amount": "22113972037624",
"amount_formatted": "22113972.03",
"decimals": 6,
"verified_contract": false
}
],
"count": 2,
"last_updated": "2026-07-06T11:00:12Z",
"stale": false,
"loading": false
}
},
"meta": {
"request_id": "req_5162c7cf7f87",
"cached": false,
"cache_age_seconds": 0,
"version": "1.0.0",
"timestamp": "2026-07-06T11:01:57Z"
}
}
{
"success": true,
"data": {
"active_holdings": {
"tokens": [],
"count": 0,
"last_updated": null,
"stale": false,
"loading": true
}
},
"meta": {
"request_id": "req_9aa1917e433b",
"cached": false,
"cache_age_seconds": 0,
"version": "1.0.0",
"timestamp": "2026-07-06T11:02:10Z"
}
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | missing_parameter | address is missing. |
| 400 | invalid_parameter | blockchain missing or invalid. |
| 404 | not_found | The wallet is not tracked by CabalSpy. |
| 401 | unauthorized | API key missing. |
| 403 | forbidden | API key invalid or credits exhausted. |
| 429 | rate_limited | Rate limit exceeded. |
⌘I

