Skip to Content

Trade

Public market data: list tradeable properties, fetch property detail (order book snapshot, recent trades, session volume, market hours), and paginated candle history. No authentication required.

Endpoints

MethodPathDescription
GET/api/tradeList tradeable properties
GET/api/trade/:tokenNameProperty market detail
GET/api/trade/:tokenName/candlesPaginated OHLCV candle history

For longer-form property disclosure (header, overview, documents), see Info. For live order book and trade streams, see WebSocket.


List tradeable properties

GET /api/trade

Returns every tradeable property with market data and a trailing-24h hourly sparkline (candlesticks), plus the active payment token address. For full chart history at other resolutions, use Candle history below. The list sparkline is not a substitute.

Request

import axios from 'axios'; const response = await axios.get('https://api.loafmarkets.com/api/trade'); console.log(response.data);

Parameters

ParameterTypeRequiredDescription
None-NoNo parameters for this endpoint.

Response

interface TradeResponse { properties: TradePropertyItem[]; paymentTokenAddress: string; } interface TradePropertyItem { propertyId: number; tokenName: string; assetName: string; ticker: string; contractAddress: string | null; streetAddress: string; country: string; latitude: number; longitude: number; propertyType: string; status: 'PENDING' | 'LIVE' | 'DELISTED'; totalTokens: number; headerImageUrl: string; videoUrl: string; marketPrice: number; dailyReferencePrice: number | null; volume24h: number; // session-to-date settled notional rentalYieldPercentage: number | null; candlesticks: Array<{ time: number; open: number; high: number; low: number; close: number; volume: number; }>; }

Example response:

{ "properties": [ { "propertyId": 42, "tokenName": "opera", "assetName": "Sunset Villa", "ticker": "OPR", "contractAddress": "0xabc…", "streetAddress": "12 Ocean Ave", "country": "AU", "latitude": -33.86, "longitude": 151.21, "propertyType": "APARTMENT", "status": "LIVE", "totalTokens": 10000, "headerImageUrl": "https://cdn.example.com/header.jpg", "videoUrl": "", "marketPrice": 167.49, "dailyReferencePrice": 165.0, "volume24h": 1204.5, "rentalYieldPercentage": 5.2, "candlesticks": [] } ], "paymentTokenAddress": "0xdef…" }

Errors

StatusCodeDescription
500internal_errorUnexpected server error.

Public endpoint; no API key required. volume24h is session-to-date settled notional (resets at market open), not a strict trailing 24h window.

Get your starting point here, then switch to the live feed. Call this endpoint once to load current mark price and session volume, then subscribe to WebSocket markprice:{tokenName} and volume:{tokenName} for updates — those live feeds only send changes, not the full picture.


Property market detail

GET /api/trade/:tokenName

Full market detail for one property: nested property metadata, selector list, current order book snapshot, recent trades, session volume, payment token, and market-hours metadata. Candle history is not included; fetch it from Candle history.

Request

import axios from 'axios'; const tokenName = 'opera'; const response = await axios.get( `https://api.loafmarkets.com/api/trade/${tokenName}`, ); console.log(response.data);

Parameters

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

Response

interface PropertyResponse { propertyList: Array<{ assetName: string; tokenName: string; ticker: string; streetAddress: string; suburb: string; status: string; }>; property: { propertyId: number; tokenName: string; assetName: string; ticker: string; contractAddress: string | null; totalTokens: number; tokensIssued: number; rentalYieldPercentage: number | null; streetAddress: string; videoUrl: string; status: 'PENDING' | 'LIVE' | 'DELISTED'; isHalted: boolean; }; paymentTokenAddress: string; volume24h: number; orderBook: { bids: Array<{ price: number; quantity: number; orderId?: number }>; asks: Array<{ price: number; quantity: number; orderId?: number }>; } | null; recentTrades: Array<{ tradeId: number; propertyId: number; aggressorSide: 'BUY' | 'SELL'; price: number; quantity: number; timestamp: number; }>; dailyReferencePrice: number | null; marketOpenTime: string; marketCloseTime: string; marketTimezone: string; marketClosedDays: string[]; maxSlippageBps: number; }

Example response:

{ "propertyList": [ { "assetName": "Sunset Villa", "tokenName": "opera", "ticker": "OPR", "streetAddress": "12 Ocean Ave", "suburb": "Bondi", "status": "LIVE" } ], "property": { "propertyId": 42, "tokenName": "opera", "assetName": "Sunset Villa", "ticker": "OPR", "contractAddress": "0xabc…", "totalTokens": 10000, "tokensIssued": 8000, "rentalYieldPercentage": 5.2, "streetAddress": "12 Ocean Ave", "videoUrl": "", "status": "LIVE", "isHalted": false }, "paymentTokenAddress": "0xdef…", "volume24h": 1204.5, "orderBook": { "bids": [{ "price": 167.0, "quantity": 10 }], "asks": [{ "price": 168.0, "quantity": 5 }] }, "recentTrades": [], "dailyReferencePrice": 165.0, "marketOpenTime": "09:00", "marketCloseTime": "17:00", "marketTimezone": "Australia/Sydney", "marketClosedDays": ["Saturday", "Sunday"], "maxSlippageBps": 300 }

Errors

StatusCodeDescription
400validation_errorInvalid tokenName.
404not_foundProperty not found.
500internal_errorUnexpected server error.

Public endpoint; no API key required. orderBook may be null when the book is empty.

Don’t poll this in a loop. Repeated automated requests get blocked by our bot protection, and non-browser clients can’t recover. For live updates, use the WebSocket instead → orderbook:{tokenName} and trades:{tokenName}.


Candle history

GET /api/trade/:tokenName/candles

Paginated OHLCV candle history for a property. Candles are aggregated server-side to the requested resolution.

Request

import axios from 'axios'; const tokenName = 'opera'; const response = await axios.get( `https://api.loafmarkets.com/api/trade/${tokenName}/candles`, { params: { resolution: '1h', countBack: 200 } }, ); console.log(response.data.candles.at(-1)); // latest candle // Page older: pass previous response.oldestTs as `to` while hasMore is true

Parameters

ParameterTypeRequiredDescription
tokenNamestringYes(path) Lowercase property tokenName (letters a-z only, max 20). Not the ticker.
resolutionstringYes(query) Bucket size: 1m, 5m, 15m, 1h, 4h, 1d, or 1w.
tonumberNo(query) Return only candles strictly older than this unix-seconds timestamp. Omit for the most recent candles.
countBacknumberNo(query) How many candles to return (server default 1000).

Response

interface CandleHistoryResponse { resolution: string; candles: Array<{ time: number; open: number; high: number; low: number; close: number; volume: number; }>; // oldest → newest oldestTs: number | null; hasMore: boolean; }

Example response:

{ "resolution": "1h", "candles": [ { "time": 1718000000, "open": 165.0, "high": 168.5, "low": 164.2, "close": 167.49, "volume": 42.5 } ], "oldestTs": 1718000000, "hasMore": true }

Errors

StatusCodeDescription
400validation_errorInvalid tokenName or resolution.
404not_foundProperty not found.
500internal_errorUnexpected server error.

Public endpoint; no API key required. To page backwards, pass the previous response’s oldestTs as to while hasMore is true.

Get your starting point here, then switch to the live feed. Call this endpoint once (or page it) to load chart history, then subscribe to WebSocket chart:{tokenName} for updates — the live feed only adds new candles, not the full history.

Last updated on