Skip to main content
Manage and query portfolios for virtual users — abstracted identities that represent balance-tracking or CEX-linked accounts. Virtual user endpoints follow the same patterns as Portfolio but use virtual:<id> addresses.
Pro subscription required. Virtual users are a Pro feature. Create and manage them in the Octav Pro app — the API provides read-only access.
Interactive Playground: Test these endpoints in the API Playground. Get your API key at data.octav.fi
Cost: 1 credit per call (list) · 1 credit per virtual user address (portfolio)

List Virtual Users

Returns all virtual users belonging to the authenticated API user.

Endpoint

GET https://api.octav.fi/v1/virtual-users

Parameters

No query parameters required — returns all virtual users for the authenticated user.

Response

Returns an array of virtual user objects.
address
string
Virtual user identifier in virtual:<id> format. Use this value in the portfolio endpoint’s addresses parameter.
type
string
The virtual user type (e.g. BALANCE, CEX)
label
string
User-defined label for the virtual user

Example Request

curl -X GET "https://api.octav.fi/v1/virtual-users" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

[
  {
    "address": "virtual:a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "type": "BALANCE",
    "label": "My Virtual Portfolio"
  },
  {
    "address": "virtual:f9e8d7c6-b5a4-3210-fedc-ba0987654321",
    "type": "CEX",
    "label": "Exchange Account"
  }
]

Virtual Users Portfolio

Fetch portfolios for one or more virtual users. Works identically to GET /v1/portfolio but uses virtual user addresses instead of wallet addresses.

Endpoint

GET https://api.octav.fi/v1/virtual-users/portfolio

Parameters

addresses
string
required
Comma-separated virtual user addresses (from the list endpoint). Format: virtual:<id>. Max 10.
addresses=virtual:a1b2c3d4-e5f6-7890-abcd-ef1234567890,virtual:f9e8d7c6-b5a4-3210-fedc-ba0987654321
aggregated
boolean
default:"false"
Return a single reduced portfolio across all virtual usersWhen true, returns a single-element array with merged holdings from all specified virtual users
waitForSync
boolean
default:"false"
Wait for fresh data if cache is stale
  • false: Return cached data immediately (recommended)
  • true: Wait for sync if data is older than 1 minute
includeImages
boolean
default:"false"
Include image URLs for chains, assets, and protocolsUseful for displaying logos in your application UI
includeExplorerUrls
boolean
default:"false"
Include blockchain explorer URLs for assets and transactionsLinks to Etherscan, Arbiscan, etc. for easy navigation

Response

Same portfolio schema as GET /v1/portfolio. Returns an array of portfolio objects (one per virtual user), or a single-element array if aggregated=true.

Portfolio Object

address
string
The virtual user address (virtual:<id>)
networth
string
Total portfolio net worth in USD
cashBalance
string
Available cash balance
dailyIncome
string
Income generated today
dailyExpense
string
Expenses incurred today
fees
string
Total fees in native asset
feesFiat
string
Total fees in USD
lastUpdated
string
Last sync timestamp (milliseconds since epoch)
openPnl
string
Unrealized profit/loss (if available, otherwise “N/A”)
closedPnl
string
Realized profit/loss (if available, otherwise “N/A”)
totalCostBasis
string
Total cost basis of holdings (if available, otherwise “N/A”)
assetByProtocols
object
Assets organized by protocol (wallet, lending, staking, etc.)Each protocol contains:
  • key: Protocol identifier
  • name: Protocol display name
  • value: Total value in USD
  • assets[]: Array of asset holdings
chains
object
Assets organized by blockchainEach chain contains:
  • key: Chain identifier (e.g., “ethereum”, “arbitrum”)
  • name: Chain display name
  • value: Total value on this chain
  • protocols[]: Protocols with positions on this chain

Example Request

curl -X GET "https://api.octav.fi/v1/virtual-users/portfolio?addresses=virtual:a1b2c3d4-e5f6-7890-abcd-ef1234567890&aggregated=true&includeImages=true" \
  -H "Authorization: Bearer YOUR_API_KEY"

Example Response

[
  {
    "address": "virtual:a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "cashBalance": "0",
    "dailyIncome": "0",
    "dailyExpense": "0",
    "fees": "0.05",
    "feesFiat": "160.25",
    "lastUpdated": "1715173392020",
    "networth": "28450.30",
    "assetByProtocols": {
      "wallet": {
        "key": "wallet",
        "name": "Wallet",
        "value": "18200.00",
        "assets": [
          {
            "balance": "3.2",
            "symbol": "ETH",
            "price": "3200.50",
            "value": "10241.60",
            "contractAddress": "0x0000000000000000000000000000000000000000",
            "chain": "ethereum"
          },
          {
            "balance": "7958.40",
            "symbol": "USDC",
            "price": "1.00",
            "value": "7958.40",
            "contractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
            "chain": "ethereum"
          }
        ]
      },
      "aave_v3": {
        "key": "aave_v3",
        "name": "Aave V3",
        "value": "10250.30",
        "assets": [
          {
            "balance": "10250.30",
            "symbol": "USDT",
            "price": "1.00",
            "value": "10250.30",
            "contractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7",
            "chain": "ethereum"
          }
        ]
      }
    },
    "chains": {
      "ethereum": {
        "key": "ethereum",
        "name": "Ethereum",
        "value": "28450.30",
        "protocols": ["wallet", "aave_v3"]
      }
    }
  }
]

Data Freshness

The Virtual Users Portfolio endpoint uses the same caching strategy as Portfolio:
Cache Duration: 1 minuteWhen data is less than 1 minute old:
  • Cached data returned immediately
  • Response time: under 100ms
When data is more than 1 minute old:
  • Cached data returned immediately
  • Background sync initiated for next request
  • Next request gets fresh data
With waitForSync=true:
  • Waits for sync if data is stale
  • Returns data less than 1 minute old
  • Response time: Variable (1-10 seconds)
For most use cases:
  • Use default waitForSync=false
  • Data fresher than 1 minute is sufficient
  • Fast response times
For real-time tracking:
  • Set waitForSync=true when you need the absolute latest data
  • Accept longer response times
  • Consider rate limits

Use Cases

Discover virtual users and fetch their portfolios in a single flow:
// Step 1: List all virtual users
const usersResponse = await fetch(
  'https://api.octav.fi/v1/virtual-users',
  { headers: { 'Authorization': `Bearer ${apiKey}` } }
);
const virtualUsers = await usersResponse.json();

// Step 2: Fetch aggregated portfolio for all virtual users
const addresses = virtualUsers.map(u => u.address).join(',');
const portfolioResponse = await fetch(
  `https://api.octav.fi/v1/virtual-users/portfolio?addresses=${addresses}&aggregated=true`,
  { headers: { 'Authorization': `Bearer ${apiKey}` } }
);
const portfolio = await portfolioResponse.json();
console.log(`Total Net Worth: $${portfolio[0].networth}`);

Error Responses

Invalid parameters provided.
{
  "error": "Bad Request",
  "message": "addresses parameter is required"
}
Common causes:
  • Missing addresses parameter (portfolio endpoint)
  • Invalid address format (must be virtual:<id>)
  • More than 10 addresses in single request
Authentication failed.
{
  "error": "Unauthorized",
  "message": "Invalid API key"
}
Solution: Check your API key in the Authorization header
Attempted to access virtual users that don’t belong to the authenticated API user.
{
  "error": "Forbidden",
  "message": "One or more virtual user addresses do not belong to this account"
}
Solution: Only use virtual user addresses returned by GET /v1/virtual-users for your API key
Rate limit exceeded.
{
  "error": "Rate limit exceeded",
  "message": "You have exceeded your rate limit",
  "retry_after": 60
}
Solution: Wait for the specified time or implement retry logic
Insufficient credits.
{
  "error": "Insufficient credits",
  "message": "Please purchase more credits to continue"
}
Solution: Purchase more credits at data.octav.fi

Portfolio

Retrieve portfolio holdings for wallet addresses

Historical Portfolio

View portfolio value at specific dates

Status

Check when portfolio was last synced

Credits

Check your remaining API credits