> Source: https://ashareapi.com/en/docs/guides/nodejs-ashare-quotes/  ·  Markdown version for LLMs / AI agents

Tutorial

# A-Share Data in Node.js / TypeScript with the Official SDK
 The official Node SDK is live: `npm install ashareapi`. Five endpoints need no key, it has zero runtime dependencies (native `fetch`), ships full TypeScript types, returns arrays of objects, accepts forgiving symbol formats, and 5 exception types tell you exactly what to do.

## Install

 bash
```
npm install ashareapi
# or: pnpm add ashareapi / yarn add ashareapi
```

-
 Requires **Node.js >= 18** (native `fetch`; 20 LTS or newer recommended)

-
 **Zero runtime dependencies** — about 12 KB installed, no supply-chain surface

-
 **Both ESM and CommonJS** work (`import` and `require`), with bundled `.d.ts` types

-
 ⚠️ **Server-side only** (Node scripts / Next.js server routes / backends) — in a browser your API key would be exposed, so no browser build is provided

## Up and running in 30 seconds (free endpoints need no key)
 Five free data endpoints: `quote` / `kline` / `hot` / `marketOverview` / `changedist` — **no signup, no key**, works immediately after install.

 TypeScript / ESM (runs as-is)
```
import { AShareAPI } from "ashareapi";

const cli = new AShareAPI(); // free endpoints need no key
const bars = await cli.quote("sh600667"); // real-time quote
console.log(bars[0]); // { date, open, last, high, low, volume, amount, turnover }

console.log(await cli.kline("600667.SH", "day", 5)); // any symbol format works
console.log(await cli.hot(10)); // hot list
console.log(await cli.changedist()); // up/down distribution
```

## CommonJS form (`require`)

 JavaScript (CJS)
```
const { AShareAPI } = require("ashareapi");

(async () => {
 const cli = new AShareAPI();
 const rows = await cli.kline("sh600667", "day", 3);
 console.log(rows[0].date, rows[0].last);
})();
```

-
 The `exports` map declares both `import` and `require` entry points — **you do not have to change module systems to use this package**

## Two naming styles, same methods (drop-in from the Python SDK)
 Multi-word methods expose **snake_case aliases** (identical to the Python SDK names) — both spellings are the same method, so code copied from the Python docs works unchanged.
 |
| | camelCase (JS convention) | snake_case (same as Python SDK) | Endpoint

| | `marketOverview(type)` | `market_overview(type)` | `/v1/market-overview`

| | `marginTrade(code, date)` | `margin_trade(code, date)` | `/v1/margin-trade`

| | `blockTrade(code, date)` | `block_trade(code, date)` | `/v1/block-trade`

| | `sectorValuation(code)` | `sector_valuation(code)` | `/v1/sector-valuation`

| | `industryChain(mode, topic, code)` | `industry_chain(mode, topic, code)` | `/v1/industry-chain`

 `marketOverview(type)`
 `market_overview(type)`
 `/v1/market-overview`

 `marginTrade(code, date)`
 `margin_trade(code, date)`
 `/v1/margin-trade`

 `blockTrade(code, date)`
 `block_trade(code, date)`
 `/v1/block-trade`

 `sectorValuation(code)`
 `sector_valuation(code)`
 `/v1/sector-valuation`

 `industryChain(mode, topic, code)`
 `industry_chain(mode, topic, code)`
 `/v1/industry-chain`

## Symbol formats: three spellings accepted
 |
| | You write | Normalised to | Notes

| | `sh600667` | `sh600667` | Native form (market prefix + code)

| | `600667.SH` | `sh600667` | Common suffix style, converted automatically

| | `600667` | `sh600667` | Bare 6 digits inferred from the first digit: 5/6 → Shanghai, 0/3 → Shenzhen, 4/8 → Beijing

 `sh600667`
 `sh600667`
 Native form (market prefix + code)

 `600667.SH`
 `sh600667`
 Common suffix style, converted automatically

 `600667`
 `sh600667`
 Bare 6 digits inferred from the first digit: 5/6 → Shanghai, 0/3 → Shenzhen, 4/8 → Beijing

## Key-required endpoints

 TypeScript
```
import { AShareAPI } from "ashareapi";

const cli = new AShareAPI({ apiKey: "ct-your-key" }); // or set ASHARE_API_KEY
const rows = await cli.screen("", "low_pe", 10, "ROETTM"); // expr, preset, limit, orderby
console.table(rows);

console.log(await cli.fund("sh600667")); // money flow + boards + block trades + margin
console.log(await cli.finance("sh600667")); // three financial statements
console.log(await cli.lhb("institution")); // top-trader board, institutions
```

-
 Get a key on the [pricing page](https://ashareapi.com/pricing/) (from ¥9.9)

-
 32 endpoints = 32 methods, named after the endpoint (`/v1/margin-trade` → `marginTrade()`)

-
 Full list in the [endpoint reference](https://ashareapi.com/endpoints/)

## Return shape: an array of objects (not a DataFrame)
 For the full envelope (with `elapsed_ms` / `source` / `tier`) construct with `new AShareAPI({ raw: true })` — methods then return the raw response object instead of an array.

 TypeScript
```
const rows = await cli.kline("sh600667", "day", 3);
// [
// { date: '2026-09-23', open: '20.10', last: '20.59', high: '20.72', low: '19.45', ... },
// { date: '2026-09-22', open: '20.63', last: '19.87', ... },
// { date: '2026-09-21', ... }
// ]
```
 |
| | | Python SDK | Node.js SDK

| | Default return | `pandas.DataFrame` (or `list[dict]` without pandas) | **`Row[]`** (array of objects) — except `finance` (`Row[][]`) and `shareholder` / `calendar` (`{ tables, data }`)

| | Accessing values | `df["last"]` / `df.head()` | `rows[0].last` / `rows.map(...)`

| | Sync or async | Synchronous | **Everything returns a Promise** (`await`)

 Default return
 `pandas.DataFrame` (or `list[dict]` without pandas)
 **`Row[]`** (array of objects) — except `finance` (`Row[][]`) and `shareholder` / `calendar` (`{ tables, data }`)

 Accessing values
 `df["last"]` / `df.head()`
 `rows[0].last` / `rows.map(...)`

 Sync or async
 Synchronous
 **Everything returns a Promise** (`await`)

## Error handling: 5 exception types that each say what to do

 TypeScript
```
import { AShareAPI, AuthError, RateLimitError,
 UpstreamError, EmptyResultError } from "ashareapi";

const cli = new AShareAPI();
try {
 const rows = await cli.fund("sh600667");
} catch (e) {
 if (e instanceof AuthError) console.log(e.message); // 401 -> key-required endpoint, get a key
 else if (e instanceof RateLimitError) console.log(e.message); // 429 -> slow down / solve a PoW challenge / upgrade
 else if (e instanceof UpstreamError) console.log(e.message); // upstream fetch failed (failed over, not billed) -> retry once
 else if (e instanceof EmptyResultError) console.log(e.message); // no data right now (e.g. no block trades today) -> not billed
 else throw e;
}
```

-
 Built-in retries: `429` / `5xx` / network errors back off exponentially 3 times (0.5s / 1.5s / 4s)

-
 `ok:false` (upstream fetch failure) is **never retried** — the backend already failed over

 |
| | Exception | When it is thrown | What to do

| | `AuthError` | 401 / key-required endpoint called without a key | Get a key, or use the free endpoints

| | `RateLimitError` | 429, tier rate exceeded | Slow down; solve a PoW challenge; or upgrade

| | `UpstreamError` | Upstream fetch failed (we failed over, **not billed**) | One retry usually fixes it

| | `EmptyResultError` | Request succeeded but **there is no data right now** | Change conditions or retry later, **not billed**

| | `APIError` | Anything else (network / 5xx after retries) | Read the message

 `AuthError`
 401 / key-required endpoint called without a key
 Get a key, or use the free endpoints

 `RateLimitError`
 429, tier rate exceeded
 Slow down; solve a PoW challenge; or upgrade

 `UpstreamError`
 Upstream fetch failed (we failed over, **not billed**)
 One retry usually fixes it

 `EmptyResultError`
 Request succeeded but **there is no data right now**
 Change conditions or retry later, **not billed**

 `APIError`
 Anything else (network / 5xx after retries)
 Read the message

## Using it in a Next.js server route (server-side only)

 app/api/quote/route.ts
```
import { NextResponse } from "next/server";
import { AShareAPI, AuthError, RateLimitError } from "ashareapi";

const cli = new AShareAPI(); // reads process.env.ASHARE_API_KEY

export async function GET(request: Request) {
 const code = new URL(request.url).searchParams.get("code") ?? "sh600667";
 try {
 const [quote, technical] = await Promise.all([cli.quote(code), cli.technical(code)]);
 return NextResponse.json({ ok: true, code, quote: quote[0], technical: technical[0] });
 } catch (e) {
 if (e instanceof AuthError) return NextResponse.json({ ok: false, error: "Missing or invalid key" }, { status: 401 });
 if (e instanceof RateLimitError) return NextResponse.json({ ok: false, error: "Rate limited" }, { status: 429 });
 throw e;
 }
}
```

-
 Keep the key in a server-side env var (`.env.local`) — **never** in `NEXT_PUBLIC_*`, which ships to the browser bundle

-
 `Promise.all` fetches several endpoints concurrently — much faster than sequential calls

## Common mistakes and boundaries

-
 `401` on a key-required endpoint → no key supplied: only 5 endpoints are free

-
 `429` → anonymous limits are low (5/min); one PoW challenge (`cli.challenge()`) raises it to 60/min, or upgrade the tier

-
 **`EmptyResultError` is not a failure**: it means "there is genuinely no such data right now" (e.g. no block trades today) — not billed, do not treat it as an error

-
 **Forgetting `await`**: every method returns a Promise, so `console.log(cli.quote(...))` prints a Promise, not data

-
 **Data date**: on a market holiday the date will not say "today"; read the `date` field to know which session the data belongs to

-
 **Units**: `volume` is in lots (×100 = shares) · `amount` is CNY · ratio fields are percentages (`20` = 20%)

-
 **Minute bars**: only daily / weekly / monthly are provided; minute-level is out of scope (stated plainly)

## FAQ
 Is the SDK free?
 **The SDK itself is free (MIT)**. Five free endpoints (quote / K-line / hot list / market overview / up-down distribution) need **no key and no signup**. The other 25 endpoints need an API key (from ¥9.9); the SDK charges nothing extra.

 Do I need to install dependencies?
 No. **Zero runtime dependencies** — it only uses Node native `fetch` (hence Node >= 18). About 12 KB installed, no transitive dependencies and no supply-chain surface.

 Can I call it from the browser?
 Technically our API allows cross-origin calls, but it is **not recommended and not supported**: calling from a browser puts your API key in front-end code and network requests, which is the same as publishing it. Call from the server (Node / Next.js server route / cloud function) and pass results to the front end. No browser build is provided on purpose.

 Are the TypeScript types complete?
 Yes. Bundled `.d.ts` files: your editor autocompletes all 32 methods and their parameters. Common row types (`Row` / `QuoteRow` / `Envelope`) are exported, so `import type { Row } from "ashareapi"` works.

 How is this different from the Python SDK?
 **Same backend, same 32 methods, same 5 exception types, same retry policy.** The only differences are language conventions: the JS methods are primarily camelCase (with snake_case aliases), **everything returns a Promise**, and results are arrays of objects rather than DataFrames.

 How do I upgrade?
 `npm install ashareapi@latest`. For the latest version and the full change history, see the [changelog](/en/changelog).

 Last updated: 2026-09-23
 Code and return shapes come from real runs of the SDK (installed 2026-09-23 from the packed tarball and verified in both ESM and CJS: quote returned 30 rows, hot 3 rows, marketOverview("valuation") 8 rows, and a key-required endpoint correctly threw AuthError without a key).

 Read next

-
[Endpoint reference (32 endpoints, fields and samples)](/en/endpoints)

-
[Python SDK (pip install ashareapi)](/en/docs/guides/python-sdk)

-
[Python quotes: 3 approaches compared](/en/docs/guides/python-ashare-quotes)

-
[Error codes](/en/docs/errors)

 [← All tutorials](/en/docs/guides)
