NewTimeSpace API
Full request (Base URL: https://www.newtimespace.com). No registration and no API key are required; both GET and POST are supported (POST may carry a JSON body):
GET https://www.newtimespace.com/api/v1/article/getArticles?language=en&q=AI&page=1&limit=10&format=json
The list endpoint returns only a short summary for each article; call the details endpoint to read the full text. Response example (JSON):
{
"status": "success",
"articles": [
{
"article_id": "1024",
"title": "Xiaomi unveils next-generation smart cockpit",
"summary": "Xiaomi today unveiled its next-generation smart cockpit solution...",
"publish_time": "2026-09-22T10:00:00+08:00",
"url": "https://www.newtimespace.com/en/news/1024.html",
"category": "Tech"
}
],
"pagination": { "page": 1, "limit": 10, "total": 137, "total_pages": 14 },
"request_id": "a1b2c3d4e5f60718",
"server_time": "2026-09-23T09:30:00+08:00",
"applied_filters": {
"q": "AI", "category": "", "category_ids": [], "language": "en",
"start_date": "", "end_date": "", "sort": "publish_time", "order": "desc",
"format": "json", "fields": []
},
"warnings": []
}
Responses are standard UTF-8 JSON with no BOM and Content-Type: application/json, so you can hand the bytes straight to json.loads. Every response carries request_id (equal to the X-Request-Id response header); include it when reporting an issue.
import json, urllib.request
raw = urllib.request.urlopen(
"https://www.newtimespace.com/api/v1/article/getArticles?format=json"
).read()
data = json.loads(raw.decode("utf-8")) # standard UTF-8 JSON, no BOM
for a in data["articles"]:
print(a["article_id"], a["publish_time"], a["title"])
print(data["pagination"]) # use total_pages as the paging stop condition
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
q | string | No | Search keyword, fuzzy-matched against title and summary. Pass a single core term (e.g. "Xiaomi"); avoid spaces and AND/OR/NOT operators | '' |
category | string | No | Category name (exact match, case-sensitive); must pair with language (see below) | '' |
language | string | No | Output language: zh-cn (Simplified, default), zh-hk (Traditional), en (English). Unknown values fall back to zh-cn | zh-cn |
start_date | string | No | Start date (YYYY-MM-DD, inclusive of 00:00:00 that day) | '' |
end_date | string | No | End date (YYYY-MM-DD, inclusive of 23:59:59 that day) | '' |
page | integer | No | Page number (starting from 1). A page beyond the total returns an empty array without an error | 1 |
limit | integer | No | Page size (1-100); out-of-range returns HTTP 400 (PARAMETER_OUT_OF_RANGE). 10-20 recommended to save tokens | 10 |
sort | string | No | Sort field: publish_time (publish time) or id (article ID) | publish_time |
order | string | No | Sort direction: desc (descending) or asc (ascending) | desc |
fields | string | No | Sparse fieldset (comma-separated) to trim list output and save tokens. Allowed: article_id,title,summary,publish_time,url,category. article_id is always returned. Empty = all fields | '' |
format | string | No | Response format: json or xml; other values are treated as json. The Accept header does not affect the format — always pass it explicitly | json |
Backward compatibility: the legacy title parameter is merged into q; the legacy date parameter is treated as a single-day range (start_date = end_date = date); the legacy sortBy (date | id) maps to sort (date → publish_time).
Category values (must be paired with language)
| language | Valid categories |
|---|---|
| zh-cn | ETF、财经、新股、科技、出海、新时空研究院 |
| zh-hk | ETF、新股、科技、出海. 财经 and 新时空研究院 return an empty result under zh-hk (both simplified and traditional forms) |
| en | ETF, Finance, IPO, Research, Tech, Overseas |
Mismatched combinations (e.g. zh-cn with IPO) or nonexistent category values return HTTP 200 with an empty array and a message; the warnings field then lists the valid categories for that language so you can self-correct. Note: articles with category 财经 / 新时空研究院 do appear in zh-hk list results, yet filtering zh-hk by these two values returns an empty array — to get these categories in Traditional Chinese, fetch language=zh-hk without category and filter on the category field yourself.
Each item in articles contains six fields:
| Field | Description |
|---|---|
article_id | Article ID (always returned); use it to call the details endpoint |
title | Title |
summary | Summary (not the full text); call the details endpoint to read the full text |
publish_time | Publish time, ISO-8601 Beijing time (GMT+8), e.g. 2026-09-22T10:00:00+08:00 |
url | Canonical article link; use it for citations, do not build your own |
category | Category name |
Top-level envelope fields:
| Field | Description |
|---|---|
status | "success" on success |
articles | Array of articles (an empty array when there are no matches) |
pagination | { page, limit, total, total_pages } |
request_id | Request tracking ID (equals the X-Request-Id header); include it when reporting issues |
server_time | Server time, ISO-8601 |
applied_filters | The filters the server actually applied (q, category, category_ids, language, start_date, end_date, sort, order, format, fields); verify them against your intent |
warnings | Non-fatal hints (e.g. category not matched, en summary fell back to Chinese) |
message | Optional; present on empty results |
XML output (format=xml, list endpoint only; no envelope or pagination). Each field is wrapped in CDATA and Content-Type is text/xml:
<?xml version="1.0" encoding="UTF-8"?>
<articles>
<article>
<article_id><![CDATA[1024]]></article_id>
<title><![CDATA[Xiaomi unveils next-generation smart cockpit]]></title>
<summary><![CDATA[Xiaomi today unveiled its next-generation smart cockpit solution...]]></summary>
<publish_time><![CDATA[2026-09-22T10:00:00+08:00]]></publish_time>
<url><![CDATA[https://www.newtimespace.com/en/news/1024.html]]></url>
<category><![CDATA[Tech]]></category>
</article>
</articles>
pagination contains page (current page), limit (page size), total (total matches) and total_pages (total pages). Example: {"page": 1, "limit": 10, "total": 137, "total_pages": 14}.
Stop on total_pages, not on an empty array. A page beyond the total returns HTTP 200 with an empty array and no error; using "got an empty array" as the stop condition wastes requests. Stop paging when page >= total_pages.
No matches / mismatched combination / page beyond the total return HTTP 200 with an empty array — a normal result; do not retry. The warnings field explains why (e.g. it lists the valid categories):
{ "status": "success", "articles": [], "pagination": { "page": 1, "limit": 10, "total": 0, "total_pages": 0 }, "request_id": "a1b2c3d4e5f60718", "server_time": "2026-09-23T09:30:00+08:00", "applied_filters": { "q": "", "category": "IPO", "category_ids": [], "language": "zh-cn", "start_date": "", "end_date": "", "sort": "publish_time", "order": "desc", "format": "json", "fields": [] }, "warnings": ["category 'IPO' has no match under language 'zh-cn'"], "message": "no articles matched the given filters" }
Errors use RFC 7807 (Content-Type: application/problem+json) with a standard HTTP status code. Example (limit out of range):
{
"type": "about:blank",
"title": "Bad Request",
"status": 400,
"detail": "limit out of range: page size must be between 1 and 100.",
"error_code": "PARAMETER_OUT_OF_RANGE",
"request_id": "a1b2c3d4e5f60718",
"instance": "/api/v1/article/getArticles?limit=200",
"code": 400,
"message": "limit out of range: page size must be between 1 and 100."
}
| Trigger | HTTP | error_code |
|---|---|---|
| limit outside 1-100 | 400 | PARAMETER_OUT_OF_RANGE |
| more than 60 requests per IP per 60 seconds | 429 | RATE_LIMIT_EXCEEDED (carries Retry-After; wait accordingly) |
| unexpected server failure | 500 | INTERNAL_SERVER_ERROR |
import json, urllib.request, urllib.parse
BASE = "https://www.newtimespace.com/api/v1/article/getArticles"
DETAIL = "https://www.newtimespace.com/api/v1/article/detail"
def search(keyword, max_pages=3):
results = []
for page in range(1, max_pages + 1):
url = BASE + "?" + urllib.parse.urlencode(
{"q": keyword, "language": "en", "format": "json", "page": page})
raw = urllib.request.urlopen(url).read()
data = json.loads(raw.decode("utf-8")) # standard UTF-8 JSON, no BOM
results += data["articles"]
if page >= data["pagination"]["total_pages"]: # stop condition: total_pages
break
return results
hits = search("profit warning")
for a in hits:
print(a["publish_time"], a["title"]) # publish_time is Beijing time (GMT+8)
print(" summary:", a["summary"][:80]) # the list returns a summary only
print(" url:", a["url"]) # use this url for citations
# To read the full text, call the details endpoint (up to 10 IDs per call)
ids = ",".join(a["article_id"] for a in hits[:10])
raw = urllib.request.urlopen(DETAIL + "?article_ids=" + ids).read()
detail = json.loads(raw.decode("utf-8"))
for d in detail["data"]: # data is always an array
print(d["article_id"], d["word_count"])
print(" content (Markdown):", d["content"][:120])