Skip to Content
API ReferencePortfolio

Portfolio

Portfolio balances, positions, and fee components for the authenticated user. Cash and token amounts held against open or settling orders appear as frozen (locked) balances. See also Locked balances.

Endpoints

MethodPathDescription
GET/api/portfolio/Portfolio summary
GET/api/portfolio/componentPortfolio component
GET/api/portfolio/position/:tokenName/pnl-cardPosition PnL share card (JPEG)

Portfolio summary

GET /api/portfolio/

Returns portfolio page data for the authenticated user. The payload wraps a component object (same shape as the component endpoint below).

Request

import axios from 'axios'; const response = await axios.get('https://api.loafmarkets.com/api/portfolio/', { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` }, }); console.log(response.data);

Response

Type: PortfolioPageResponse

interface PortfolioPageResponse { component: PortfolioComponentResponse; }

See Portfolio component for the full component shape.

Errors

StatusCodeDescription
401unauthorizedMissing or invalid authentication.
500internal_errorUnexpected server error.

Requires API key authentication.

Get your starting point here, then switch to the live feed. Call this endpoint once to load current balances and positions, then subscribe to WebSocket portfolio:{userId} for updates — the live feed only sends changes, not the full picture.


Portfolio component

GET /api/portfolio/component

Returns balances, positions, fees, and recent activity lists used by the portfolio UI.

Request

import axios from 'axios'; const response = await axios.get('https://api.loafmarkets.com/api/portfolio/component', { headers: { Authorization: `Bearer ${process.env.LOAF_API_KEY}` }, }); console.log(response.data);

Response

Type: PortfolioComponentResponse

interface PortfolioComponentResponse { cash: number; // available USDC (not frozen) frozen: number; // locked USDC (open orders / settling) portfolioValue: number; portfolioPnl: number; portfolioPnlPercent: number; lifetimeVolume: number; positions: PortfolioComponentPosition[]; applicableFees: ApplicableFees; offeringOrders: OfferingOrder[]; openOrders: OrderHistoryItem[]; tradeHistory: TradeHistoryItem[]; orderHistory: OrderHistoryItem[]; transfers: TransferHistoryItem[]; } interface PortfolioComponentPosition { propertyId: number; tokenName: string; quantity: number; // tradeable (available) size totalQuantity: number; // includes reserved/frozen tokens totalTokens: number; averageEntryPrice: number; marketPrice: number; percentChange: number; percentOfPortfolio: number; propertyPnl: number; propertyPnlPercent: number; isIpoAllocation: boolean; imageUrl: string; } interface ApplicableFees { takerFeeBps: number; makerFeeBps: number; }

Balances: cash is spendable USDC. frozen is reserved against open or in-flight orders and cannot be used until the reservation clears (fill, cancel, or settlement complete). For positions, quantity is what you can trade; totalQuantity includes locked size.

Errors

StatusCodeDescription
401unauthorizedMissing or invalid authentication.
500internal_errorUnexpected server error.

Get your starting point here, then switch to the live feed. Call this endpoint once to load current balances and positions, then subscribe to WebSocket portfolio:{userId} for updates — the live feed only sends changes, not the full picture.


Position PnL card

GET /api/portfolio/position/:tokenName/pnl-card

Authenticated. Returns a JPEG share image for a position identified by lowercase tokenName (e.g. opera, not the ticker).

Response headers include Content-Type: image/jpeg and Cache-Control: private, no-store.

Parameters

ParameterTypeRequiredDescription
tokenNamestringYes(path) Lowercase property tokenName (letters a-z only, max 20).

Errors

StatusCodeDescription
401unauthorizedMissing or invalid authentication.
404not_foundNo position for that tokenName.
422Cannot render (e.g. no market price available).
500internal_errorUnexpected server error.
Last updated on