Response shapes
The payload in data comes in four different shapes — row arrays, table lists, pre-rendered text and multi-segment structures. Check the type before reading it, or you will index into a string where you should read a field, or the reverse.
The four shapes
data is not one thing. Check what type it is before deciding how to read it:
| Shape | Type of data |
How to read it |
|---|---|---|
| Row array | array, one item per row | data[0].field; more rows are data[0] → data[n] |
| Table list | array of arrays, one item per table | data[0] is the first table, data[0][0] is its first row |
| Pre-rendered text | string (markdown) | use data for display; use the extra structured / tables for programmatic access |
| Multi-segment structure | object containing tables |
read segments from data.tables; each has title / slug / rows |
A one-line rule: look at whether the first character is [, { or ".
Which of the 33 endpoints uses which shape
| Shape | Endpoints |
|---|---|
| Row array | quote · kline · minute · hot · technical · chip · profile · search · ipo · dividend · block-trade · margin-trade · orderbook · snapshot |
| Table list | finance |
| Pre-rendered text | market-overview · changedist · events · lhb · sector · sector-valuation · macro · bond · etf · dehydrated · screen |
| Multi-segment structure | shareholder · calendar |
| Object (neither array nor text) | fund · industry-chain |
| Special cases | health (no data) · usage (plain text, not JSON) · challenge (returns the challenge itself) |
The ones that trip people up
orderbook and snapshot are row arrays too, just always exactly one row. The design keeps everything a row array so clients do not need a special case for single-object endpoints — read data[0].field and you are right.
⚠️ The table above is the shape for a single code. Sending several codes changes the shape — quote / technical / profile add a code column, while chip becomes a wide table with prefixed column names (the row count does not double). See Batch fetching for details.
finance is a table list, not a multi-segment structure. data[0] / data[1] / data[2] are the income statement / balance sheet / cash-flow statement — the order is fixed. To address them by name, see the next section.
shareholder and calendar are multi-segment structures. data.tables is an ordered list of tables. ⚠️ Do not pick shareholder segments by index — A-shares and Hong Kong both have 3 segments, but they mean completely different things (A-shares: top-ten holders / top-ten float holders / holder-count stats; Hong Kong: shareholders / distribution / institutional holdings). Address them by slug.
fund is a genuine object (not text): read data.main_net, data.main_rank and so on directly.
How to read text endpoints programmatically
For text endpoints, data is human-readable markdown, but two extra fields appear alongside:
| Field | What it is |
|---|---|
structured |
The first table, as [{column: value}] |
tables |
Every table, as [[{column: value}], ...] |
data itself is unchanged — text clients keep using data, programmatic clients use structured / tables. For multi-segment output (such as calendar or macro), only tables gets you everything.
structured gives you just the first table, so use it when one table is all you need (e.g. the screen result); when there are several segments, always use tables.
Common misuses
- Treating a text endpoint as an array — for
market-overview,sectorand friendsdatais a string, sodata[0]is the first character, not the first row. - Treating a row array as an object —
quote’sdatais an array;data.lastfinds nothing, you needdata[0].last. - Addressing
financeby name — it is an order-fixed table list with no slugs; addressing by name gets you the wrong table. - Picking
shareholdersegments by index — A-shares and Hong Kong have the same segment count but different meanings; always useslug. - Forgetting
structuredholds only the first table — reading only it silently drops every later segment.
Last updated: 2026-10-07
Shapes measured endpoint by endpoint on 2026-10-07 by calling the data layer directly and printing each return type and key set; the extra structured / tables fields for text endpoints come from the server-side injection logic.