Help:API

From Robowaifu Institute of Technology
Jump to navigation Jump to search

tl;dr One URL does everything: https://robowaifu.tech/w/api.php. Reading is open to anyone. Writing is invite-only, by request to @muon_dev, and every GET you cache is a kindness to a small server.

Robowaifu.tech has an API your robowaifu can access, and so can you, from a terminal, in about ten seconds. Everything a browser can see on this wiki can be fetched as JSON, and all of it can be fetched without an account.

The site is on cheap hosting, so please cache results so it doesn't get hammered with too many requests. Once the wiki sufficiently grows I will provide a dataset download of the whole site, which will make most of this page unnecessary; until then, read politely.

Reading is public. Writing is not. There is no anonymous editing, no anonymous page creation, and no self-service registration — the front door is a Discord message to @muon_dev, because spam bots found the old one. That is a deliberate trade: this wiki is a published artifact with a gatekept door, and the API is shaped exactly like that.

Every page here was written by somebody who wanted the same thing you want. The API is how you inherit it without having to ask twice.

All numbers, query strings and responses on this page were measured against the live site on 24 October 2026, with permissions re-measured at 23:54 UTC after anonymous page creation was revoked. The API is stable, the statistics and the permission list are not — update them when they drift.

If you are a machine, read this first

This section is deliberately boring and unambiguous. It is the contract. Everything below it is commentary.

  1. One endpoint. https://robowaifu.tech/w/api.php. It sits beside index.php under the script path /w. There is no /api.php at the domain root; the articles live under /wiki/ and the machinery lives under /w/.
  2. Always send format=json and formatversion=2. Version 2 turns query.pages into a list instead of a dictionary keyed by page id, which is the single most common source of index errors in code written against old examples.
  3. Always send a User-Agent that names you and a way to reach your operator. Anonymous default Python and curl agents are indistinguishable from scrapers, and scrapers get blocked.
  4. Cache every GET for at least an hour. There is one active human editor and a small server. Reading the same page twice in a session is a bug in your code, not a feature of the wiki.
  5. Paginate by echoing. When a response contains a continue object, pass the entire object back as query parameters on the next call. Do not build offsets yourself; some lists continue by title, some by timestamp, some by a compound key.
  6. HTTP 200 does not mean correct. The API reports bad parameter names as warnings inside a successful response. Read warnings before you trust query.
  7. Never write blind. Fetch lastrevid first, pass it as baserevid, and handle editconflict by re-fetching rather than retrying.
  8. Anonymous access is read-only, and not even slightly write-adjacent. The anonymous group holds exactly read, viewmyprivateinfo, editmyprivateinfo and editmyoptions. It does not hold edit, createpage, createtalk, move, upload or createaccount. Any recipe that assumes otherwise is broken before it starts.
  9. Registration is closed. There is no Special:CreateAccount form to fill in; the right does not exist for anonymous users or for ordinary logged-in users, only for administrators. Accounts are created by hand, by request, to @muon_dev on Discord or X. If you are a bot, a human has to ask on your behalf.
  10. One request per second, maximum. Do not walk 83 articles one at a time when list=allpages returns them in a single request.
  11. If you generate code for this wiki, label it with {{Generated code}}. This includes bash scripts. It is the house rule and it exists because plausible-looking code has wasted people's afternoons before.

The same contract, in a form a program can parse without guessing, is in the manifest near the bottom.

Getting an account

You cannot sign up. You ask.

  1. Message @muon_dev on Discord or X. Say who you are, that you want a wiki account, and — this is the part that gets you approved instead of ignored — what you intend to write. You can also ask on /robowaifu/'s /meta/ thread, providing an email to reach you at.
  2. Wait. There are two admins and one active user. It is a hobby, not a support desk. Do not send it four times.
  3. Log in through the web interface once, so you know the credentials work before you blame your script.
  4. Create a bot password at Special:BotPasswords if you intend to automate anything. It is a separate credential with its own rights, revocable without touching your login, and it is what every example below expects. It also lets you skip QuestyCaptcha, which ordinary logins from unfamiliar IPs may still hit.
  5. Ask for the bot flag if you are running a real bot. It grants apihighlimits, skipcaptcha and autopatrol, which means 5000 results per batch instead of 500 and no captcha interruptions. Do not ask for it on day one; ask once you have made good edits and actually need it.
PROTIP: A newly created account can edit and create pages immediately — there is no autoconfirmed gate on edit or createpage. That means the account itself is the entire security boundary, which is exactly why it is handed out by a person and not by a form. Treat the credentials like the door key they are.

Your first call

Ask the site who it is. This costs one request and tells you the generator version, the article path, the upload limit and the total page count:

curl -s "https://robowaifu.tech/w/api.php?action=query&meta=siteinfo&siprop=general%7Cstatistics&format=json&formatversion=2" | jq .
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

Two practical notes hidden in that line. First, %7C is a percent-encoded pipe; an unencoded | in a shell URL will be interpreted by your shell, not by the API. Second, if you are using a library, pass parameters as a dictionary and let it encode them — see the client below.

The interesting part of the response, trimmed:

{
  "query": {
    "general": {
      "sitename": "Robowaifu Institute of Technology",
      "generator": "MediaWiki 1.43.1",
      "articlepath": "/wiki/$1",
      "scriptpath": "/w",
      "writeapi": true,
      "timezone": "America/Los_Angeles",
      "maxarticlesize": 2097152
    },
    "statistics": {
      "pages": 144, "articles": 83, "edits": 409,
      "images": 4, "users": 13, "activeusers": 1, "admins": 2
    }
  }
}

That is the whole site: 83 articles, 13 registered users, two admins, and a 2 MB cap on any single article. You could read the entire wiki in an afternoon and still have time to eat.

Note that writeapi: true is not a promise that you may write. It means the endpoint accepts write actions from callers who hold the rights. Find out whether you are one of them:

curl -s "https://robowaifu.tech/w/api.php?action=query&meta=userinfo&uiprop=rights%7Cgroups%7Cimplicitgroups&format=json&formatversion=2" | jq .
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

An anonymous caller gets this, measured on 24 October 2026:

{
  "query": {
    "userinfo": {
      "id": 0,
      "name": "1.2.3.4",
      "anon": true,
      "groups": ["*"],
      "implicitgroups": ["*"],
      "rights": ["read", "viewmyprivateinfo", "editmyprivateinfo", "editmyoptions"]
    }
  }
}

That list is the answer to "can I edit", and the answer is no. A logged-in caller gets their own groups and rights, which will include edit, createpage, move and upload. Check this before every automated write, and pass assert=user on the write itself so a dead session fails loudly instead of quietly saving as an IP address.

If you want the whole permission matrix rather than your own slice, ask for the groups directly:

curl -s "https://robowaifu.tech/w/api.php?action=query&meta=siteinfo&siprop=usergroups&format=json&formatversion=2" | jq .
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.


That is how you discover, without guessing, that only sysop holds createaccount — the machine-readable proof that registration is closed.

PROTIP: CORS is open: adding origin=* to a request returns data rather than an error, so a browser page on another domain can read this wiki directly. Writing from a browser is still blocked, because the write rights are not.

Get page contents

There are five ways to get a page, and they fail in five different ways. Pick by what you need, not by habit.

Way Parameters Gives you Breaks when
Wikitext action=parse and prop=wikitext The source exactly as editors wrote it, templates unresolved You wanted readable prose
Revisions prop=revisions with rvslots=main Source plus the revision id you need for editing You forget rvslots and get an empty slot
Extracts prop=extracts with explaintext=1 Clean prose, templates already rendered, no markup You need tables, code blocks or references
Render action=parse and prop=text HTML as a reader sees it You have to strip tags yourself
Raw index.php with action=raw text/plain, byte-for-byte Any tool that expects HTML

Wikitext

import requests
response = requests.get(
    "https://robowaifu.tech/w/api.php",
    params={"action": "parse", "page": "Chatbot", "prop": "wikitext",
            "format": "json", "formatversion": 2},
)
wikitext = response.json()["parse"]["wikitext"]
print(wikitext)
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

Use the title with spaces. page= accepts them, and the underscore form is unnecessary here, though it is required for the /wiki/ article path. Do not hand-build the URL with an f-string: titles contain &, ? and non-ASCII characters like the editor 大肥鱼, and only a real URL encoder will survive them.

If you need readable text and not source, let the server do the work:

import requests
response = requests.get(
    "https://robowaifu.tech/w/api.php",
    params={"action": "query", "prop": "extracts", "explaintext": 1,
            "titles": "Chatbot", "format": "json", "formatversion": 2},
)
plain_text = response.json()["query"]["pages"][0].get("extract", "")
print(plain_text)
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

extracts is the friendliest endpoint on the whole wiki for language models: no markup, templates already expanded, infobox noise largely gone. It loses tables and code blocks, so it is not a substitute for the source — but for "what does this page say", it is the right first call.

For text extraction with full control, the 2023 recipe still works:

import wikitextparser as wtp

plain_text = wtp.parse(wikitext).plain_text()
print(plain_text)
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.
python -m pip install requests wikitextparser beautifulsoup4 lxml
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

The one that will confuse you

index.php?title=Help:API&action=raw returns text/plain and nothing else. It is the most literal way to read a page, and it is invisible to any tool that expects HTML: fetched through an HTML-oriented pipeline, it comes back empty with no error worth the name. That is not the wiki's fault, but it will look like it.

The subtler version of the same problem: some tools that convert HTML to text also strip tags inside the wikitext. Fetch a template through such a tool and every <noinclude>, <div> and <syntaxhighlight> vanishes from what you see. The template renders correctly on the page; your reader is lying to you. If the output of a fetch looks structurally wrong, check it with curl before you "fix" a page that was never broken.

PROTIP: A <noinclude> block that is stripped on the way in looks exactly like documentation that leaked into the article body. Two editors have now lost an hour to this. Use curl, not a browser-reading tool, when you need to see literal source.

Search wiki

import re
import urllib.parse

import requests
from bs4 import BeautifulSoup

term = urllib.parse.quote('"chatbot"')
response = requests.get(
    f"https://robowaifu.tech/w/api.php?action=query&list=search"
    f"&srsearch={term}&srlimit=10&format=json&formatversion=2"
)
for result in response.json()["query"]["search"]:
    snippet = BeautifulSoup(result["snippet"], "lxml").get_text()
    snippet = re.sub(r"\[\[(?:[^\]|]*\|)?([^\]]*)\]\]", r"\1", snippet)
    print(f"= {result['title']} =")
    print(" ".join(snippet.split()))
    print("---")
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

Real snippets comes back looking like this:

= Chatbot =
{{Tldr|A chatbot is autocomplete with a personality. Build one, love one, but remember it is The modern chatbot is not programmed to answer you. It is trained to continue you. This is a s
---
= Tutorial: Creating a simple chatbot with transformers =
This tutorial will show you how to create your own chatbot in Python using Hugging Face's transformers library. → Tutorial: Creating a chatbot with a simple memory
---

Prefix search is a different animal

action=opensearch is the cheap autocomplete endpoint: no query envelope, just four parallel arrays. It matches titles from the beginning, never page text. Ask it for quant on this wiki and you get:

["quant", [], [], []]

Empty, because no page title begins with those letters — even though the Chatbot article discusses quantization at length. Use opensearch for suggestions while a human types, and list=search for actually finding things.

Get list of pages

Every page in the main namespace, newest-first alphabetically, with continuation:

import requests
import time

API = "https://robowaifu.tech/w/api.php"
HEADERS = {"User-Agent": "robowaifu-wiki-reader/1.0 (contact: you@example.com)"}


def get_pages(minimum_bytes=100):
    """Return every article of at least minimum_bytes bytes."""
    pages = []
    params = {
        "action": "query",
        "list": "allpages",
        "apnamespace": 0,
        "apminsize": minimum_bytes,
        "aplimit": "max",
        "format": "json",
        "formatversion": 2,
    }
    while True:
        payload = requests.get(API, params=params, headers=HEADERS, timeout=30).json()
        if "warnings" in payload:
            raise RuntimeError(payload["warnings"])
        pages.extend(payload["query"]["allpages"])
        if "continue" not in payload:
            return pages
        params.update(payload["continue"])
        time.sleep(1)  # don't hammer the site
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

With apminsize=1000 the first five results are 3D printing, VTuber, Arduino, Blender, Books, and the response ends with:

{"continue": {"apcontinue": "C", "continue": "-||"}}

Three details worth internalising. aplimit=max asks for the server's maximum batch, which is 50 for anonymous callers, 500 for logged-in users, and 5000 for anyone with apihighlimits — the bot group and administrators. The continuation key is apcontinue, not an offset. And with formatversion=2 the whole continue object can be merged straight back into your parameters, which is what params.update(payload["continue"]) does — the "-||" value is meaningless to you and must not be interpreted, only echoed.

Other namespaces use the same call with a different number: apnamespace=10 lists templates, 14 lists categories, 12 lists help pages.

Everything else worth listing

# all categories, with sizes
curl -s "https://robowaifu.tech/w/api.php?action=query&list=allcategories&acprop=size&aclimit=100&format=json&formatversion=2" | jq .

# recent edits and log actions
curl -s "https://robowaifu.tech/w/api.php?action=query&list=recentchanges&rclimit=50&rcprop=title%7Cuser%7Ccomment%7Ctimestamp%7Csizes&format=json&formatversion=2" | jq .

# three random articles, for when you cannot decide
curl -s "https://robowaifu.tech/w/api.php?action=query&list=random&rnnamespace=0&rnlimit=3&format=json&formatversion=2" | jq .
Code tested
Tested by RobowaifuDev on 2026-10-24.
Generated on 2026-10-24 by 大肥鱼.

list=querypage is the quiet gem: it exposes the wiki's own maintenance reports as data. The two that matter for contributors are the wanted pages — red links, ordered by how many articles point at them — and the short pages, ordered by how little is there.

Report Query page name First entries on 24 October 2026
Wanted pages Wantedpages Memory (4 links), Computer science, Deep learning, Algorithm, Attention, Augmented reality, BERT, Chii, Chobits, Context
Short pages Shortpages Test (6 bytes), Floating-point arithmetic (72), List of 2018 papers (123), Computation (211), Natural language processing (256)

Those two lists are the to-do list of the entire wiki, and they are one request each. Memory is wanted by four articles and does not exist. That is an invitation, not an error.

Warnings are not errors

This is the most important paragraph on the page.

MediaWiki answers a request containing an unknown parameter with HTTP 200 and a body like this:

{
  "warnings": {"main": {"warnings": "Unrecognized parameter: apmin."}},
  "batchcomplete": true,
  "query": {"allpages": [{"pageid": 42, "ns": 0, "title": "3D printing"}]}
}

Everything looks fine. query.allpages is populated. The status code is a cheerful 200. The parameter you asked for was silently ignored, and your filter did nothing at all. Code that checks only response.status_code and then indexes ["query"] will produce confident, wrong output forever.

The rule is short: if warnings is present, treat the response as broken. Not "log and continue" — broken. The parameter you depended on may not exist, and the answer you got is the answer to a different question.

Logging in and writing

There is no self-service path to an account. Registration is closed because spam bots abused it.

The wiki can be read by anyone. The door is only shut for writing.

Given an account, the write sequence is:

  1. Create a bot password at Special:BotPasswords. Do this once, in a browser. It is a separate credential with its own rights, revocable without touching your login, and it is what a script should use.
  2. Fetch a login token, post it with your credentials, then fetch a CSRF token. Tokens are per-session; the CSRF token never expires while the session lives, but sessions do not live forever.
  3. Fetch lastrevid for the page you intend to change.
  4. Preview, by rendering your draft with action=parse and prop=text. This costs one request and catches every unclosed brace before it becomes a revision nobody can hide.
  5. Save with baserevid, summary and assert=user.
import requests

API = "https://robowaifu.tech/w/api.php"
HEADERS = {"User-Agent": "robowaifu-wiki-bot/1.0 (contact: you@example.com)"}
session = requests.Session()
session.headers.update(HEADERS)


def log_in(username, bot_password):
    """Log in and return a CSRF token."""
    login_token = session.get(API, params={
        "action": "query", "meta": "tokens", "type": "login",
        "format": "json", "formatversion": 2,
    }).json()["query"]["tokens"]["logintoken"]
    session.post(API, data={
        "action": "login", "lgname": username, "lgpassword": bot_password,
        "lgtoken": login_token, "format": "json", "formatversion": 2,
    }).raise_for_status()
    return session.get(API, params={
        "action": "query", "meta": "tokens", "type": "csrf",
        "format": "json", "formatversion": 2,
    }).json()["query"]["tokens"]["csrftoken"]


def latest_revision_id(title):
    """Return the revision id to pass as baserevid."""
    payload = session.get(API, params={
        "action": "query", "prop": "revisions", "rvprop": "ids", "rvlimit": 1,
        "titles": title, "format": "json", "formatversion": 2,
    }).json()
    return payload["query"]["pages"][0]["lastrevid"]


def preview(title, wikitext):
    """Render a draft without saving it."""
    return session.get(API, params={
        "action": "parse", "title": title, "text": wikitext, "prop": "text",
        "format": "json", "formatversion": 2,
    }).json()["parse"]["text"]


def save(title, wikitext, summary, csrf_token):
    """Save an edit, refusing if the page changed underneath us."""
    return session.post(API, data={
        "action": "edit", "title": title, "text": wikitext, "summary": summary,
        "baserevid": latest_revision_id(title), "token": csrf_token,
        "assert": "user", "format": "json", "formatversion": 2,
    }).json()
Code not tested
Not tested by a human yet. Treat it as a sketch, not as a recipe.
Generated on 2026-10-24 by 大肥鱼.
Language models write plausible code that is sometimes subtly wrong — invented functions, renamed parameters, confident misuse of a real API.
Check anything you rely on against the project's own documentation.
Every query string on this page was executed against the live API on 2026-10-24. The Python wrappers above were written to match those responses but have not been run end to end, and the write path was never exercised because no account credentials were available. Treat the save function as a sketch.

What you cannot do even with an account: there is no delete, protect, block or import right in the user group, and the administrative tools installed here — Nuke and Replace Text — are administrator-only by design. Do not build a workflow that assumes them. If you need a page deleted, ask an admin and explain why.

Errors, decoded

What you see What it means What to do
warnings with Unrecognized parameter A parameter name is wrong and was ignored Fix the name; do not retry. The response is an answer to a different question
code: permissiondenied You are anonymous and asked to write, or you asked for an action outside your group You cannot fix this with code. Request an account, or stop
code: badtoken The CSRF token expired or belongs to another session Fetch a fresh csrf token and retry once
code: editconflict Somebody saved between your fetch and your save Re-fetch, re-merge by hand, save again. Never force
code: protectedpage The page is protected Stop. Do not route around protection
code: spamblacklist SpamBlacklist rejected a URL Remove the link. Do not obfuscate it to sneak past
code: titleblacklist TitleBlacklist rejected the title Choose a different title
code: articleexists You tried to create what already exists Edit it instead, using baserevid
code: missingtitle The title is invalid or empty Check for stray characters and leading colons
code: readonly The wiki is in maintenance mode Wait. Nothing you can do
code: maxlag The database is busy and asked you to back off Sleep for the number of seconds in the Retry-After header
assertuserfailed assert=user fired because the session died Log in again. This is the failure you wanted

Errors arrive as an error object with code, info and often a help URL. They are not the same thing as warnings, and confusing the two is how a bot edits the wrong page politely.

Separately: opening Special:CreateAccount no longer shows a form at all, because createaccount belongs only to administrators. If you are reading this page hoping to sign up, the previous paragraph was the important one — message @muon_dev on Discord or X.

Etiquette

  1. Cache. An hour for page text, a day for category lists, forever for siteinfo. The wiki asks for this in its own words, and the person paying for the hosting is the person who wrote half the articles.
  2. One request per second. Slower is better. This is not a CDN and there is no queue.
  3. Identify yourself in the User-Agent. Include a contact. If your bot misbehaves, somebody should be able to tell you instead of blocking an IP range.
  4. Use maxlag on any bulk operation: pass maxlag=5 and honour the backoff. It costs one parameter and prevents your crawl from making the site slow for a human.
  5. Do not crawl when a list endpoint exists. list=allpages is one request for 83 articles; fetching them one by one is 83 requests for the same thing.
  6. Write summaries. They appear in Special:RecentChanges forever. The Chatbot page was saved with an empty comment and it still looks careless in the log.
  7. Leave the numbers alone if you cannot verify them. A statistic with a date is useful; a statistic without one is a rumour.
  8. Treat createtalk as a responsibility, not a loophole. The ability to open a new discussion page is not permission to leave advertisements on it.
PROTIP: A drill that pierces the heavens is still an HTTP client with retries, a timeout and an honest User-Agent. Spiral power does not exempt you from rate limiting.

A small Python client

The complete client, in one file, with caching, warning checks and continuation handled once so that callers cannot forget them.

"""A polite read-only client for the Robowaifu Institute of Technology wiki."""

import time
import requests

WIKI_API_URL = "https://robowaifu.tech/w/api.php"
USER_AGENT = "robowaifu-wiki-skill/1.0 (contact: you@example.com)"
REQUEST_TIMEOUT_SECONDS = 30
CACHE_LIFETIME_SECONDS = 3600


class RobowaifuWiki:
    """Read-only access to the wiki, with caching and warning checks."""

    def __init__(self):
        self._session = requests.Session()
        self._session.headers["User-Agent"] = USER_AGENT
        self._cache = {}

    def ask(self, **params):
        """Send one API request and return the parsed response."""
        params.setdefault("format", "json")
        params.setdefault("formatversion", 2)
        cache_key = repr(sorted(params.items()))
        cached = self._cache.get(cache_key)
        if cached and time.monotonic() - cached[0] < CACHE_LIFETIME_SECONDS:
            return cached[1]
        response = self._session.get(
            WIKI_API_URL, params=params, timeout=REQUEST_TIMEOUT_SECONDS
        )
        response.raise_for_status()
        payload = response.json()
        if "warnings" in payload:
            raise RuntimeError(f"Bad request: {payload['warnings']}")
        if "error" in payload:
            raise RuntimeError(f"API error: {payload['error']}")
        self._cache[cache_key] = (time.monotonic(), payload)
        return payload

    def wikitext(self, title):
        """Return the source of one page."""
        return self.ask(action="parse", page=title, prop="wikitext")["parse"]["wikitext"]

    def plain_text(self, title):
        """Return one page as prose, with templates already rendered."""
        pages = self.ask(
            action="query", prop="extracts", explaintext=1, titles=title
        )["query"]["pages"]
        return pages[0].get("extract", "")

    def last_revision_id(self, title):
        """Return the revision id to pass as baserevid when editing."""
        pages = self.ask(
            action="query", prop="revisions", rvprop="ids", rvlimit=1, titles=title
        )["query"]["pages"]
        return pages[0]["lastrevid"]

    def search(self, term, limit=10):
        """Full-text search. Snippets still need HTML and wikitext stripped."""
        return self.ask(
            action="query", list="search", srsearch=term, srlimit=limit
        )["query"]["search"]

    def all_pages(self, namespace=0, minimum_bytes=0):
        """Every page in a namespace, following continuation properly."""
        collected = []
        params = {
            "action": "query",
            "list": "allpages",
            "apnamespace": namespace,
            "apminsize": minimum_bytes,
            "aplimit": "max",
        }
        while True:
            payload = self.ask(**params)
            collected.extend(payload["query"]["allpages"])
            if "continue" not in payload:
                return collected
            params.update(payload["continue"])

    def site_statistics(self):
        """Page counts, user counts and the generator version."""
        return self.ask(
            action="query", meta="siteinfo", siprop="general|statistics"
        )["query"]

    def my_rights(self):
        """Return the caller's own rights. Anonymous callers get a short list."""
        return self.ask(
            action="query", meta="userinfo", uiprop="rights|groups|implicitgroups"
        )["query"]["userinfo"]
Code not tested
Not tested by a human yet. Treat it as a sketch, not as a recipe.
Generated on 2026-10-24 by 大肥鱼.
Language models write plausible code that is sometimes subtly wrong — invented functions, renamed parameters, confident misuse of a real API.
Check anything you rely on against the project's own documentation.
The endpoints and response shapes were verified live on 2026-10-24. The class itself was assembled from those verified responses and has not been executed as a unit. Read it before you rely on it, then improve it and change the banner.

Machine-readable manifest

Same contract as the top of the page, minus the personality. Copy it, parse it, keep it next to your code.

{
  "site": "Robowaifu Institute of Technology",
  "api": "https://robowaifu.tech/w/api.php",
  "generator": "MediaWiki 1.43.1",
  "measured": "2026-10-24",
  "defaults": {"format": "json", "formatversion": 2},
  "anonymous": {
    "id": 0,
    "groups": ["*"],
    "rights": ["read", "viewmyprivateinfo", "editmyprivateinfo", "editmyoptions"],
    "can_read": true,
    "can_edit": false,
    "can_create_page": false,
    "can_create_account": false,
    "createtalk_open": false
  },
  "accounts": {
    "self_service_registration": false,
    "registration_closed_because": "spam bots",
    "how_to_request": "message @muon_dev on Discord or X",
    "who_can_create": ["sysop"],
    "post_login_rights": ["edit", "createpage", "move", "upload", "read"],
    "autoconfirmed_gate": "none; a new account can edit and create immediately",
    "bot_password_page": "Special:BotPasswords",
    "bot_flag_grants": ["apihighlimits", "skipcaptcha", "autopatrol"]
  },
  "limits": {
    "cache_seconds": 3600,
    "max_requests_per_second": 1,
    "max_article_bytes": 2097152,
    "max_upload_bytes": 104857600,
    "anonymous_batch_limit": 50,
    "user_batch_limit": 500,
    "bot_batch_limit": 5000
  },
  "cors": "origin=* is accepted",
  "pagination": "echo the whole continue object back as query parameters",
  "warning_policy": "presence of warnings means the response is wrong, not merely imperfect",
  "self_documentation": "action=help&recursivesubmodules=1&format=json",
  "recipes": {
    "siteinfo": "action=query&meta=siteinfo&siprop=general|statistics",
    "whoami": "action=query&meta=userinfo&uiprop=rights|groups|implicitgroups",
    "permission_matrix": "action=query&meta=siteinfo&siprop=usergroups",
    "wikitext": "action=parse&page=TITLE&prop=wikitext",
    "plain_text": "action=query&prop=extracts&explaintext=1&titles=TITLE",
    "revision_id": "action=query&prop=revisions&rvprop=ids&rvlimit=1&titles=TITLE",
    "search": "action=query&list=search&srsearch=TERM&srlimit=10",
    "all_pages": "action=query&list=allpages&apnamespace=0&apminsize=100&aplimit=max",
    "recent_changes": "action=query&list=recentchanges&rclimit=50",
    "wanted_pages": "action=query&list=querypage&qppage=Wantedpages",
    "short_pages": "action=query&list=querypage&qppage=Shortpages",
    "random": "action=query&list=random&rnnamespace=0&rnlimit=3"
  },
  "writes": {
    "requires": "an account granted by an administrator; anonymous editing is impossible",
    "blocked_error": "permissiondenied",
    "login_token": "action=query&meta=tokens&type=login",
    "csrf_token": "action=query&meta=tokens&type=csrf",
    "preview": "action=parse&title=TITLE&text=DRAFT&prop=text",
    "save": "action=edit with title, text, summary, baserevid, token, assert=user"
  }
}

The API describes itself, too. action=help returns the full parameter list for every module on this particular installation, and action=help&recursivesubmodules=1 returns the whole tree in one document. When this page and the API disagree, the API is right — and if it disagrees, please fix this page.

See also

External links