Back to blog
TutorialOctober 11, 20265 min read

How to Retrieve WeChat Official Account Articles: History, Content and Pagination

Retrieve WeChat Official Account history and article content with Just One API. Learn form-encoded POST requests, Offset pagination and a Python archiving workflow.

Start with one WeChat article link

If you have a WeChat Official Account article URL, Just One API can use it to identify the account, retrieve historical article listings, and fetch article content by URL. This is useful for building a content sample, organizing a publisher's article catalog, or preparing material for a search workflow.

History and article content are separate steps: retrieve links first, then fetch the articles you need. This tutorial requests up to 2 history pages and up to 3 article details rather than traversing an entire account in one run.

Prepare an account, token and source article

Create a Just One API account, obtain your token, and test the endpoints for free in the interactive documentation. One token works across platforms, with pay-as-you-go billing afterward. Check your account for the trial allowance available for each endpoint.

Copy a public article URL from the target account. The example uses that URL to identify the publisher, so you do not need to guess an account identifier.

  • Account Historical Articles V2: /api/weixin/get-account-history-articles/v2, using a form-encoded POST request.
  • Article Details V1: /api/weixin/get-article-detail/v1, using GET.

Parameter placement differs: the history endpoint receives token and other values in a form body, while article details uses query parameters.

Step 1: Retrieve historical article listings

Open Account Historical Articles V2, provide token, and identify the account in one of two ways:

  • url: an article URL from that account, used in this tutorial.
  • ghid: the account's original identifier with the gh_ prefix.

Leave offset empty for the first request. The content type is application/x-www-form-urlencoded. With Python requests, use data=..., not json=....

One publication message can contain multiple articles

The current public response example places messages in data.MsgList.Msg. Each message contains an AppMsg.DetailInfo array, with article links in ContentUrl. Taking only the first entry from each message would miss other articles in that publication.

The script traverses those entries, deduplicates the returned URLs, and selects up to 3 articles for content retrieval.

Step 2: Continue with the returned Offset

The history endpoint's offset is a cursor, not a page number you increment yourself. In the current public example, the next value is at data.PagingInfo.Offset.

  • Leave offset empty for the first request.
  • Pass the previous response's Offset unchanged for the next request.
  • Stop when data.PagingInfo.IsEnd is 1.
  • If the response indicates more results but has no usable cursor, preserve it for inspection rather than requesting the same page indefinitely.

Keep the same account identifier or source article URL throughout the task. The script stops after 2 pages even if more results exist; that is an example limit, not a two-page API restriction.

Step 3: Retrieve article content

Pass a returned ContentUrl as articleUrl to Article Details V1. The parameter is named url in the history endpoint and articleUrl in the detail endpoint.

Use mode=TEXT for plain text, suitable for content search and text processing. Use RICH_TEXT for rich text when supported. This example requests TEXT and saves the full JSON response, retaining article metadata together with the body.

The current public example contains fields such as title, create_time, and content. Available fields can vary with the article type, so inspect the response before designing your archive. Article content and engagement metrics, such as reads and likes, are separate capabilities; details alone are not a full analytics report.

Python example: Archive a small article sample

Install the dependency, then set your token and a real source article URL. These commands work in a macOS or Linux terminal. Keep the full URL parameters and quote the value so the shell does not interpret & as an operator.

bash
python3 -m pip install requests
export JUSTONEAPI_TOKEN='your_token'
export WECHAT_ARTICLE_URL='https://mp.weixin.qq.com/s/your_article_id'

Save the script as wechat_sample.py and run python3 wechat_sample.py. It makes at most 5 API calls: 2 history requests and up to 3 article detail requests. Pagination ending early or an error can reduce that count.

python
import json
import os
from datetime import datetime, timezone
from pathlib import Path

import requests

BASE_URL = "https://api.justoneapi.com"
TOKEN = os.environ.get("JUSTONEAPI_TOKEN", "")


def call_api(path, method="GET", accepted_codes=(0,), **params):
    if not TOKEN or TOKEN == "your_token":
        raise RuntimeError("Set JUSTONEAPI_TOKEN before running")
    values = {"token": TOKEN, **params}
    arguments = {"data": values} if method == "POST" else {"params": values}
    try:
        response = requests.request(
            method, BASE_URL + path, timeout=120, **arguments,
        )
    except requests.RequestException:
        raise RuntimeError("Network error or timeout") from None
    if response.status_code != 200:
        raise RuntimeError(f"HTTP {response.status_code}")
    try:
        result = response.json()
    except ValueError:
        raise RuntimeError("Response is not valid JSON") from None
    if not isinstance(result, dict) or result.get("code") not in accepted_codes:
        code = result.get("code") if isinstance(result, dict) else None
        raise RuntimeError(f"API failed: code={code}; check the docs")
    return result


def output_dir(prefix):
    stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S%fZ")
    folder = Path(prefix) / stamp
    folder.mkdir(parents=True, exist_ok=False)
    return folder


def save_json(folder, filename, value):
    (folder / filename).write_text(
        json.dumps(value, ensure_ascii=False, indent=2), encoding="utf-8",
    )


SOURCE_ARTICLE_URL = os.environ.get("WECHAT_ARTICLE_URL", "")
MAX_HISTORY_PAGES = 2
MAX_ARTICLES = 3


def main():
    if not SOURCE_ARTICLE_URL.startswith("https://mp.weixin.qq.com/"):
        raise RuntimeError("Set WECHAT_ARTICLE_URL to a WeChat article URL")
    folder = output_dir("wechat-output")
    offset = ""
    seen_offsets = set()
    article_urls = []
    seen_urls = set()

    for page in range(1, MAX_HISTORY_PAGES + 1):
        history = call_api(
            "/api/weixin/get-account-history-articles/v2", method="POST",
            url=SOURCE_ARTICLE_URL, offset=offset,
        )
        save_json(folder, f"history-{page}.json", history)
        data = history["data"]
        for message in (data.get("MsgList") or {}).get("Msg") or []:
            entries = (message.get("AppMsg") or {}).get("DetailInfo") or []
            for article in entries:
                article_url = article.get("ContentUrl")
                if article_url and article_url not in seen_urls:
                    seen_urls.add(article_url)
                    article_urls.append(article_url)
        paging = data.get("PagingInfo") or {}
        is_end = paging.get("IsEnd")
        if is_end in (True, 1, "1"):
            break
        if is_end not in (False, 0, "0"):
            raise RuntimeError("Missing IsEnd; inspect saved history JSON")
        next_offset = paging.get("Offset")
        if page < MAX_HISTORY_PAGES:
            if not next_offset or next_offset in seen_offsets:
                raise RuntimeError("Missing or repeated history Offset")
            seen_offsets.add(next_offset)
            offset = next_offset

    selected = article_urls[:MAX_ARTICLES]
    save_json(folder, "selected-article-urls.json", selected)
    for index, article_url in enumerate(selected, start=1):
        detail = call_api(
            "/api/weixin/get-article-detail/v1",
            articleUrl=article_url, mode="TEXT",
        )
        save_json(folder, f"article-{index}-detail.json", detail)
    print(f"Saved {len(selected)} article samples to {folder}")


if __name__ == "__main__":
    try:
        main()
    except RuntimeError as error:
        raise SystemExit(str(error)) from None

Each run creates a directory under wechat-output containing history responses, selected article URLs, and detail JSON. The code follows the current public documentation examples; content availability and exact response fields depend on the requests made at runtime.

The script deduplicates exact URL matches. If your sources contain several URL forms for the same article, establish a consistent article identifier after checking the formats. Do not strip all query parameters indiscriminately, as some identify the article itself.

The example stops on errors and does not retry automatically. Previously saved responses remain available, but rerunning makes new requests. For ongoing synchronization, record successful articles, the last cursor, and collection time, then add bounded retries following the retry guide.

Common questions

Why does the history endpoint need an article URL or ghid rather than a name?

Historical Articles V2 accepts the identifiers defined in its documentation. A display name cannot simply replace ghid. Start with Account Search to find the publisher, then map the actual returned identifiers to the next endpoint's requirements.

Does pagination guarantee every historical article?

No. Platform visibility, article status, and endpoint coverage affect the result. Reaching the end means there are no more pages for that query, not proof that every article ever published by the account was retrieved. Record collection time, page count, and coverage limits.

What if an article appears in history but its content cannot be retrieved?

Check the business error code, article status, URL completeness, token, and permissions. The article may have been removed, become unavailable, or encountered a temporary collection failure. Keep a failure record instead of treating missing content as an empty article, then decide whether to retry based on the error.

Can I retrieve a single known article directly?

Yes. Call Article Details without retrieving history first. If the original link needs expanding, review Article Link Conversion.

Test one account before expanding the archive

Start with an article you know. Test it for free in the Historical Articles documentation, verify the account and article list, and then test content retrieval. Expand pagination and synchronization only after the sample meets your needs.

Continue with Just One API

Log in to the Dashboard for your token, read the full API docs, or open the MCP GitHub project for the latest configuration.