# WeChat Article Scraper: Full Text, Markdown & Images (No Login) (`kizukidata/wechat-article-reader`) Actor

Read WeChat Official Account articles from mp.weixin.qq.com links: title, account, author, publish time, Original mark, IP region, full text, Markdown and images. Use it for China market research or LLM pipelines; failed pages are free. No read counts, likes or comments. Not affiliated with Tencent.

- **URL**: https://apify.com/kizukidata/wechat-article-reader.md
- **Developed by:** [Kizuki](https://apify.com/kizukidata) (community)
- **Categories:** Social media, News
- **Features:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.12 / 1,000 articles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### What does WeChat Article Scraper do?

The **WeChat Article Scraper** reads public WeChat Official Account (公众号) articles from the links you give it and returns one row per article: title and summary, the account (name, biz id, `gh_` id, WeChat ID, description, avatar), author, publish time, the Original (原创) mark, the IP region and hashtags, the broadcast the article was sent in and its position there, the full text and a simple Markdown version, the image URLs, the cover image and a canonical link, with no login and no WeChat app.

- **Articles made of images come back as articles.** A post whose body is only images carries its title, account, publish time and `images`, with `text` as an empty string and `charCount` 0. It is charged like any other article.
- **The account behind the article.** Each row carries the account's WeChat ID, its one-line description and its avatar beside the name and biz id, plus the Original (原创) mark, the IP region the publisher shows and the article's hashtags.
- **Markdown you can index.** `markdown` keeps paragraphs, bold, links and images, so a row can go straight into a document store or a prompt.
- **HTML for re-publishing.** With **Also return the body as HTML** on, `contentHtml` is the same body as cleaned HTML with direct image URLs, ready to show again or save; it is off by default.
- **Reason rows are free.** A deleted, taken-down, expired, private or unreadable page returns one row with a fixed reason, and that row is not charged.
- **Batch speed.** In our test runs on 2026-11-13, ten articles usually took 20 to 60 seconds (one run took 94), and one article on the default input took 8 to 22 seconds. Rows are written as each article finishes.

Try it with an empty input: it reads one sample article.

WeChat Article Scraper is an independent tool. It is not affiliated with, endorsed by or sponsored by Tencent or WeChat.

### What data can you get?

| Group | Fields |
|---|---|
| Identity | `id`, `source`, `inputUrl`, `url`, `canonicalUrl` |
| Article | `title`, `digest`, `articleType`, `itemShowType` |
| Account | `accountName`, `accountId`, `accountUsername`, `accountWechatId`, `accountDescription`, `accountAvatar` |
| Marks and time | `author`, `isOriginal`, `ipRegion`, `hashtags`, `messageId`, `positionInMessage`, `publishedAt`, `publishedAtRaw`, `publishedAtText` |
| Body | `text`, `markdown`, `contentHtml`, `charCount` |
| Images | `images`, `coverImage`, `imageCount` |
| Status | `error`, `scrapedAt` |

- `id` is the short article id (from `/s/<id>`, or from the page itself when a long link was read), or a hash of `biz`, `mid`, `idx` and `sn` when a long link could not be read. `source` names the platform. `inputUrl` is the link as you sent it (trimmed), `url` the normalised link, and `canonicalUrl` the page's own short link when it carries one, otherwise `url`.
- `title` is the article title, `null` on a reason row except `no-content`, where the page's title, account and publish time are kept. `digest` is the summary the publisher wrote for the article's share card, `null` when it is empty. `articleType` is `article`, `video`, `image-post`, `text-post` or `other`; `itemShowType` is the page's raw item type number behind it (`0` = article).
- `accountName` is the account's display name, `accountId` its biz id (Base64, as WeChat reports it), `accountUsername` its original `gh_…` id, `accountWechatId` its WeChat ID, `accountDescription` its one-line description and `accountAvatar` its avatar URL. Each is `null` when the page does not carry it.
- `author` is the byline the page states, or `null`. `isOriginal` is `true` when the article carries the Original (原创) mark, `false` when it does not, and `null` when the page does not say. `ipRegion` is the province or country WeChat shows as the publisher's IP location. `hashtags` lists the tags without `#`, up to 50, and is empty when there are none. `messageId` is the broadcast the article was sent in, shared by the articles sent together, and `positionInMessage` is its place there (`1` = the headline article).
- `publishedAt` is ISO 8601 in China Standard Time (`+08:00`), with the page's own Unix time in `publishedAtRaw` and its display text in `publishedAtText`.
- `text` is the body as plain text, up to 200,000 characters, and an empty string when a post has no text (its pictures are in `images`). `markdown` is the same body with paragraphs, bold, links and images, up to 200,000 characters; it is `null` when `includeMarkdown` is off or on a reason row. `charCount` counts the Unicode characters (code points) of `text`, so an emoji counts once, and is `0` when there are none. `contentHtml` is the same body as cleaned HTML (paragraphs, headings, lists, tables, links, images), up to 500,000 characters, with images as direct https URLs and no scripts, styles, event handlers or tracking attributes; it is `null` when `includeHtml` is off or on a reason row, and a body over the limit is cut between blocks and ends with `<p>…</p>`.
- `images` lists image URLs in page order, up to 300: the body's images, or the picture list of an image post. `coverImage` is the article's cover image, and `imageCount` the number of entries in `images`. Images are returned as URLs, not downloaded.
- `error` is `null` on a returned article, or `{type, message}` on a page that could not be read. `scrapedAt` is when the run read the page (ISO 8601, UTC).

Every row has every field: a value the page does not provide is `null`, an empty list is `[]`, and a count with nothing to count is `0`. The Actor does not return read counts, likes, comments, follower numbers, an account's article list, keyword search results, video or audio files, or a translation of the body.

### How to use WeChat Article Scraper

1. Put the article links into **WeChat article links** (`urls`), up to 100 per run. Both the short and the long form work, and an article that appears twice is read once.
2. Set **Maximum rows** (`maxItems`, 3 by default, up to 100). Read articles and reason rows share this budget.
3. Keep **Also return Markdown** (`includeMarkdown`) on for LLM or archival use, or turn it off for plain text only.
4. Run the Actor and open the dataset, or export it to CSV, Excel or JSON.
5. Match each row to your input by `inputUrl` (the link you sent), or by `id` for a short link: rows are written as articles finish, so their order can be different.

#### Input example

```json
{
    "urls": [
        "https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"
    ],
    "maxItems": 3,
    "includeMarkdown": true
}
```

#### Output example (one row, shortened)

```json
{
    "id": "1mEx5PY_as18PYbEVmGQlQ",
    "source": "WeChat Official Accounts (mp.weixin.qq.com article page)",
    "inputUrl": "https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ",
    "url": "https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ",
    "canonicalUrl": "https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ",
    "title": "启新程‼️安徽师范大学2026级新生开学典礼隆重举行",
    "digest": null,
    "articleType": "article",
    "itemShowType": 0,
    "accountName": "安徽师范大学",
    "accountId": "MjM5Mzk3ODQ4Nw==",
    "accountUsername": "gh_460df90479de",
    "accountWechatId": "ahsd1928",
    "accountDescription": "该平台旨在为校内师生、学生家长及校外考生、校友、媒体及社会各界人士传递校园文化资讯和鲜活的校园生活等方面的图文信息，敬请关注！",
    "accountAvatar": "http://mmbiz.qpic.cn/mmbiz_png/TOSTRb0vicevj8zIEa3JOq5rh0yMNsWDY4kcVZibkgfDnAunwz2nicCL30vXnklibNuBsT5EaBZZHDicyQ2EJxvjjSA/0?wx_fmt=png",
    "author": null,
    "isOriginal": false,
    "ipRegion": "安徽",
    "hashtags": [],
    "messageId": "2652161627",
    "positionInMessage": 1,
    "publishedAt": "2026-09-13T17:13:34+08:00",
    "publishedAtRaw": "1789290814",
    "publishedAtText": "2026-09-13 17:13",
    "text": "9月12日，安徽师范大学2026级新生开学典礼在花津校区北侧田径场隆重举行。…",
    "markdown": "9月12日，安徽师范大学2026级新生开学典礼在花津校区北侧田径场隆重举行。…\n\n![11111.gif](https://mmbiz.qpic.cn/mmbiz_gif/8LPqPPrGZiaxc31dk2Wrbw8hf1KiaOmIic6ql1YTvbQzpicPlf5fNdSwT5EPQOO78yQwKxMibh7vRgnZXkGoqtT9VZaicB4cJ2888EwjW3ibqwibtRI/640?wx_fmt=gif&from=appmsg)",
    "contentHtml": null,
    "images": [
        "https://mmbiz.qpic.cn/mmbiz_gif/8LPqPPrGZiaxc31dk2Wrbw8hf1KiaOmIic6ql1YTvbQzpicPlf5fNdSwT5EPQOO78yQwKxMibh7vRgnZXkGoqtT9VZaicB4cJ2888EwjW3ibqwibtRI/640?wx_fmt=gif&from=appmsg",
        "https://mmbiz.qpic.cn/sz_mmbiz_gif/8LPqPPrGZiawkHtREWGCxdmEibR4EreS2NEvJEqHgPk7ONDibLa8Z2KeYGSMrPpQb6XtTpiaTSyPYyffAW3zibaiciatUibkEeKyznKtuicNlJ5LyfCU/640?wx_fmt=gif&from=appmsg"
    ],
    "coverImage": "https://mmbiz.qpic.cn/mmbiz_jpg/8LPqPPrGZiawkcic2b3eaM8cXMpEaACMDyzmsMCQjLl7wxjnTdfYicJz7xficWpWEjWhdH7ZaOqksmd0R6DJgNcgic6YpTCSMNnKILUnCjO7jfog/0?wx_fmt=jpeg",
    "charCount": 184,
    "imageCount": 2,
    "error": null,
    "scrapedAt": "2026-11-06T06:20:00.000Z"
}
```

The body fields `text` and `markdown` are cut with `…`, and `contentHtml` is `null` because `includeHtml` is off; `charCount` and `imageCount` are the row's own counts, and every URL in `images` is shown.

### When a page cannot be read

A page that cannot be read still comes back as one row: `text`, `markdown` and `contentHtml` are `null`, `hashtags` and `images` are empty, `charCount` and `imageCount` are `0`, and `error` carries a fixed reason and sentence. On every reason row except `no-content`, `title`, the account fields and the publish time are `null` too; `no-content` keeps them, because the post page itself was read.

| `error.type` | Meaning |
|---|---|
| `deleted` | The publisher deleted the article. |
| `violation` | WeChat removed the article for a rule violation. |
| `expired-link` | The link no longer points to a readable article. |
| `verification-required` | WeChat answered with a verification page instead of the article. |
| `empty-body` | A normal article, an image or text post, or a page whose type is not stated, where nothing of the body could be read; its fields are null or empty. |
| `no-content` | A post of another type, such as a video, with no text or images this Actor returns; its title, account and publish time are kept. |
| `wrong-page` | WeChat answered with a different article's page than the link names. |
| `unavailable` | The page could not be read for another reason, for example a page that is not public. |

- A reason row is part of the dataset, so you can see which link failed and why. It is not charged.
- A link that got no answer, a request that was refused, or a page too large to read is not a dataset row: it is listed with its reason in the run's OUTPUT record, under `failedInputs`, and it is not charged.
- `maxItems` counts reason rows too: the dataset never holds more than `maxItems` rows.
- A link that is not an `mp.weixin.qq.com` article, a duplicate entry, and an entry beyond `maxItems` are not read. They are listed in the run's OUTPUT record.
- An article whose body is only images is an article row, not a reason row, and it is charged.

### How much does it cost?

Launch pricing. WeChat Article Scraper uses **pay-per-event** pricing: you pay for each article returned (a row with `error: null`), including an article made of images only, not for the time the run takes.

| Apify plan (discount tier) | Price per 1,000 articles | Price per article |
|---|---|---|
| **Free** | $1.60 | $0.00160 |
| **Starter (Bronze)** | $1.44 | $0.00144 |
| **Scale (Silver)** | $1.28 | $0.00128 |
| **Business (Gold)** | $1.12 | $0.00112 |

Apify's Free plan includes USD 5 of monthly usage, which covers about 3,125 articles at the Free tier price, run start fees aside.

- **Run start fee**: USD 0.00005 per GB of memory per run (a run with up to 1 GB is charged once).
- A reason row is **not charged**, and neither is a duplicate, an invalid link or an article beyond `maxItems`.
- An article is charged once, after its row was written, so a retried run does not pay for it twice.
- **Maximum rows** (`maxItems`) caps the rows written in one run.

### Limits

- **URL in, article out.** The Actor reads the links you send. It does not search WeChat by keyword, follow an account's article list, or read the links inside an article.
- **100 links per run** (`urls`), and at most **100 rows** (`maxItems`, 3 by default). Read articles and reason rows share that budget.
- **Rows arrive in the order they finish.** Match a row to your input by `inputUrl` or `id`, not by position. The same article sent as both a short and a long link comes back as one row; if one of the two fails, its reason row and the article row share the same `id`.
- **The short link is the safer input.** Both forms are accepted, but a long `/s?__biz=…&mid=…&idx=…&sn=…` link without a `chksm` often comes back as a `verification-required` row, while the same article's short `/s/<id>` link is read. Those rows are free.
- **The body is cut at 200,000 characters** and `images` at 300 entries, so a very long article is not returned in full.
- **The public page only.** Read counts, likes, comments and follower numbers are not returned.
- **An empty input reads one sample article.** A run whose links all failed returns reason rows only, every one of them free.

### Integrations and API

Run the Actor from your own code or from an automation tool. Replace `<APIFY_TOKEN>` with your API token.

#### cURL

```bash
curl -X POST "https://api.apify.com/v2/acts/kizukidata~wechat-article-reader/runs?token=<APIFY_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"],"maxItems":1}'
```

Poll `GET https://api.apify.com/v2/actor-runs/<RUN_ID>` for the status, read `defaultDatasetId`, then fetch `GET https://api.apify.com/v2/datasets/<DATASET_ID>/items?format=json`.

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("kizukidata/wechat-article-reader").call(run_input={
    "urls": ["https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"],
    "maxItems": 1,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["accountName"], item["publishedAt"], item["charCount"])
```

#### JavaScript

```js
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<APIFY_TOKEN>' });
const run = await client.actor('kizukidata/wechat-article-reader').call({
    urls: ['https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ'],
    includeMarkdown: true,
    maxItems: 1,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const item of items) {
    console.log(item.error ? `${item.inputUrl}: ${item.error.type}` : `${item.title}: ${(item.markdown ?? '').slice(0, 200)}`);
}
```

#### Zapier, Make and n8n

Use the Apify integration, choose **Run Actor**, and pass the article links with `maxItems`. Add **Get dataset items** and map `title`, `accountName`, `publishedAt`, `text` or `markdown`, and `error` to your document store, CMS or LLM step. A scheduled workflow can take new links from your link list and send the rows to Notion, Slack or a vector store. Check `error` before you store a row: a reason row has no body.

#### LangChain

Load the rows as documents: use `text` or `markdown` as `page_content` and `title`, `accountName`, `author`, `publishedAt`, `isOriginal`, `ipRegion` and `canonicalUrl` as metadata. `ApifyDatasetLoader` from the Apify LangChain integration works with the run's dataset ID. Filter on `error` being `null` so only articles with a body reach the index.

#### Use it from an MCP client

The Actor is a tool on the hosted Apify MCP server. MCP URL:

```text
https://mcp.apify.com?tools=kizukidata/wechat-article-reader
```

- **Claude Code**: `claude mcp add --transport http apify "https://mcp.apify.com?tools=kizukidata/wechat-article-reader"`
- **Claude Desktop / claude.ai**: Settings → Connectors → Add custom connector, and paste the URL.
- **Cursor** (`~/.cursor/mcp.json`) and other clients that read an `mcpServers` file:

```json
{
    "mcpServers": {
        "apify": {
            "url": "https://mcp.apify.com?tools=kizukidata/wechat-article-reader"
        }
    }
}
```

- **n8n**: add an **MCP Client Tool** node to an AI Agent, set the endpoint to the URL above (HTTP Streamable), and use Bearer authentication with your Apify API token stored as an n8n credential.

The server signs you in to Apify with OAuth. A client that cannot use OAuth, such as the n8n node above, can send your Apify API token in an `Authorization: Bearer <APIFY_TOKEN>` header instead.

Two requests an agent can send as they are:

- "Give me the text of this WeChat article" with `{"urls":["https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"],"maxItems":1}`
- "Turn these two WeChat articles into Markdown for my index" with `{"urls":["https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ","https://mp.weixin.qq.com/s/0U9ZJSIsL1zEIbSF1Yu5vw"],"includeMarkdown":true,"maxItems":2}`

### Related Kizuki Actors

Other Actors from Kizuki that work well with this one:

- [note.com Scraper](https://apify.com/kizukidata/note-articles-feed) — articles from note.com, a Japanese creator platform, by creator, with likes, comments and the paid price of each article.
- [URL to Markdown](https://apify.com/kizukidata/url-to-markdown) — the pages an article links to, as clean Markdown for the same pipeline.
- [Google News Scraper](https://apify.com/kizukidata/google-news-feed) — the coverage around the topics you collect, with the publisher URL.
- [Telegram Channel Scraper](https://apify.com/kizukidata/telegram-channel-feed) — posts from public Telegram channels, with views, reactions and media.

# Actor input Schema

## `urls` (type: `array`):

Public WeChat Official Account article links, one per entry, up to 100 per run. The short form (`https://mp.weixin.qq.com/s/` plus the article id) works best; the long form with `__biz`, `mid`, `idx` and `sn` is accepted too. Account pages and other hosts are not read, and an article that appears twice is read once. An article row is charged, including one whose body is only images; a page that cannot be read returns a reason row and is free. The default holds one sample article.

## `maxItems` (type: `integer`):

Rows written in one run, 1 to 100. Read articles and reason rows share this budget, so the dataset never holds more than this many rows, and only article rows are charged. Links beyond it are not fetched and are listed in OUTPUT. The default of 3 keeps an MCP call short; one article usually takes about 10 seconds.

## `includeMarkdown` (type: `boolean`):

On (the default): each article also carries a simple Markdown body (paragraphs, bold, links, images). Off: plain text only, and the rows are smaller.

## `includeHtml` (type: `boolean`):

Off by default. When on, each article also carries `contentHtml`: the body as cleaned HTML, with direct image URLs and no scripts, styles, event handlers or tracking attributes, so it can be shown again as it is. Off keeps the rows smaller.

## `proxyConfiguration` (type: `object`):

Proxy settings for the article requests. The default uses an Apify datacenter proxy; residential proxies are not available in this Actor. Set `useApifyProxy` to `false` to run without a proxy, or give your own `proxyUrls` to send every request through them.

## Actor input object example

```json
{
  "urls": [
    "https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"
  ],
  "maxItems": 3,
  "includeMarkdown": true,
  "includeHtml": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Article rows returned by this run, one per URL; failure rows carry error.type and are not charged.

## `runSummary` (type: `string`):

Status code, counters and the input entries of this run that were skipped, not checked or could not be read.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"
    ],
    "maxItems": 3,
    "includeMarkdown": true,
    "includeHtml": false,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kizukidata/wechat-article-reader").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "urls": ["https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"],
    "maxItems": 3,
    "includeMarkdown": True,
    "includeHtml": False,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("kizukidata/wechat-article-reader").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://mp.weixin.qq.com/s/1mEx5PY_as18PYbEVmGQlQ"
  ],
  "maxItems": 3,
  "includeMarkdown": true,
  "includeHtml": false,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call kizukidata/wechat-article-reader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kizukidata/wechat-article-reader"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RG4umf6YOSkjb1BVZ/builds/IcUsixWBjUbsUFqvK/openapi.json
