Reference

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, sector and friends data is a string, so data[0] is the first character, not the first row.
  • Treating a row array as an object — quote’s data is an array; data.last finds nothing, you need data[0].last.
  • Addressing finance by name — it is an order-fixed table list with no slugs; addressing by name gets you the wrong table.
  • Picking shareholder segments by index — A-shares and Hong Kong have the same segment count but different meanings; always use slug.
  • Forgetting structured holds 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.