# Public research API v1

Base URL: `https://growthyoung.com`
Developer guide: `/developers`
Machine-readable contract: `/api/v1/openapi.json`

All data requests use GET, without authentication. Successful responses contain
`ok: true`, `data` and `meta.schema_version: 1`. Errors contain `ok: false`, `error`
and `detail`. Dates are preserved from the published content. No API request starts
an upstream collection task.

## Endpoints

| Path | Purpose | Query parameters |
| --- | --- | --- |
| `/api/v1/status` | Article count, last content revision date, radar availability and snapshot dates | None |
| `/api/v1/articles` | Searchable, paginated published article metadata | `lang`, `q`, `tag`, `page`, `page_size` |
| `/api/v1/articles/{slug}` | Metadata plus sanitized `content_html` | `lang` |
| `/api/v1/radar` | Existing public market pulse payload in a versioned envelope | None |

`lang` is `zh-CN` (default) or `en`. `q` searches Chinese and English titles,
summaries and keywords; it accepts up to 100 characters. `tag` must be a stable
topic ID listed in the OpenAPI specification. `page` starts at 1, up to 9999999;
`page_size` defaults to 20 and accepts 1–50. Unknown or repeated parameters are
rejected with HTTP 422. Do not pass article filters or `lang` to status or radar.

The article list returns `items`, `page`, `page_size`, `total`, `total_pages` and
`has_next`. Articles sort by publication date descending and then slug. No matches
or a page beyond the final page returns HTTP 200 with empty `items`. New publications
can move pagination; deduplicate by `slug`.

Article fields include `slug`, `language`, `title`, `summary`, `author`, `category`,
`keywords`, `tags`, `reading_time`, `published_at`, `updated_at` and `url`. Detail adds `content_html`; article aliases resolve to the
canonical `slug`. Only published articles are accessible. Sanitized HTML retains links
to cited sources; it does not expose local paths or unpublished drafts.

`meta.content_updated_at` is the most recent revision date among the returned
collection, or null for no matching content. In radar, `meta.generated_at` and
`data.generated_at` identify the collection snapshot. `analysis.status` indicates
whether its evidence set matches the current collection; inspect timestamps
separately for age. Status returns `meta.served_at`, which is query time only.

## Examples

When this skill sends an API request, include
`X-Research-Client: strategy-research-skill`. General API clients may omit it.
The marker is self-declared, not authentication. The server stores only daily
channel/method/status aggregates, never the raw header or query text.
Skill file requests are counted separately from actual marked API calls.

```text
GET /api/v1/articles?lang=en&q=backtest&page_size=5
GET /api/v1/articles/how-to-read-a-strategy-backtest?lang=en
GET /api/v1/articles?tag=ai-governance&page_size=5
GET /api/v1/status
GET /api/v1/radar
```

Make only the requests the question needs. Read results before issuing the next
request, separated by at least 10 seconds, up to 6 requests per minute.

## Caching and failures

Data and specification responses use `Cache-Control: public, max-age=60` and
ETag conditional requests (`If-None-Match`, HTTP 304). Status is `no-store`.
Errors are `no-store`. These are client usage recommendations, not a promised
server-side per-client rate limiter. Stop on 429 or access denial.

- 404: Unknown resource or unpublished article.
- 405: Unsupported HTTP method.
- 422: Invalid, repeated or unknown query parameter.
- 503: Missing or invalid local radar snapshot; this differs from a valid snapshot
  containing zero events.
- 500: Unable to read published content; internal error details are not exposed.

The older `/api/radar`, `/blog/{slug}.md`, `/blog/feed.xml` (Atom), and `/llms.txt`
remain available. This version does not expose an MCP service.

Blog Markdown exports are retired: `/blog/<slug>.md` returns 404. Article responses
do not include `markdown_url` or `content_markdown`; use `url` and `content_html`.
