REST API
NeoWiki's REST API lives under /rest.php/neowiki/v0/*. Requests and responses are JSON; the RDF export endpoints return TriG or Turtle instead.
Endpoints that change data act as the user of your session. To log in from a script, use a bot password with the Action API's action=login. These endpoints also need the session's CSRF token, from meta=tokens, in an X-CSRF-TOKEN header; without a valid one they answer 403.
Pre-1.0. Endpoints and payloads may change without notice; do not build third-party integrations on /neowiki/v0/* yet.
Every endpoint is also published as a complete OpenAPI 3.0 description.
Endpoints
Subjects
Read, change, and validate Subjects. New Subjects are created on a page, or together with a page of their own — see Pages and Subjects. For the body shape, see Subject format; for the form of a {subjectId}, see IDs.
| Endpoint | Description |
|---|---|
GET /neowiki | Fetch a Subject as the wiki publishes it, or at another revision. See Reading Subjects. |
GET /neowiki | Export one Subject as RDF. For format and projection, see RDF export. |
GET /neowiki | Dereference a Subject's concept URI: 303 to its RDF or to a page showing it, depending on Accept. See Dereferencing subject IRIs. |
PUT /neowiki | Replace a Subject's label and statements. |
DELETE /neowiki | Delete a Subject. |
POST /neowiki | Move a Subject to another page, keeping its ID so relations targeting it keep resolving. Body targetPageId, optional makeMainSubject and comment. Edits both pages. The Subject's Dependent Subjects move with it; moving a Dependent Subject on its own answers 422 with dependent-subject-without-host. |
PUT /neowiki | Set one Statement, leaving the Subject's label and other Statements as they are. |
DELETE /neowiki | Remove one Statement. |
POST /neowiki | Check whether a new Subject is valid, without saving it. Returns {violations: [...]} — see Validation codes. |
POST /neowiki | Check whether a change to a Subject is valid, without saving it. Returns {violations: [...]} — see Validation codes. |
POST /neowiki | Mint a batch of unused Subject IDs to assign on create, e.g. to wire relations across an interlinked import. Body count (1–1000). |
POST /neowiki | Create a Subject together with a page of its own, in one revision, as that page's main Subject. See Creating Subjects. |
GET /neowiki | List Subjects, newest first. Cursor-paginated with limit and cursor. Query: schema (only that Schema's Subjects; without it, Dependent Subjects are left out), search (case-insensitive substring of the name or page title, or case-sensitive prefix of the ID), sort (newest, name, schema, page, edited) and direction (asc, desc; ignored by newest). A search that runs longer than the wiki allows answers 503 with errorType searchTimeout; retry with a schema to search fewer Subjects. |
GET /neowiki | List the Subjects whose data was edited most recently, newest first, each once. Adding a Subject counts as editing it. Returns {"subjects": [...]}, rows as in GET /subjects but with lastEdited the time of the Subject's last edit. Query: limit (1–50, default 10). A request looks back no further than the wiki's 2,000 newest revisions, of any page, and can return fewer Subjects than limit even when more were edited within them. |
GET /neowiki | Count the Subjects of each Schema: {"counts": {"Artist": 12}}. A Schema with no Subjects is absent; one whose page is deleted or unreadable can be present. A count can lag a change by up to a minute. |
GET /neowiki | Find Subjects by name — the label, or for a Main Subject without one, the page title unless that is the ID of a Subject on the page. Other label-less Subjects and Dependent Subjects are absent. Returns each Subject's id, label and the prefixed pageTitle of the page holding it. Query: schema (only Subjects of these Schemas, pipe-separated; omit for every Schema), search (name prefix), limit. |
GET /neowiki | List the Subjects whose relations point at this one. See Referencing Subjects. |
Pages and Subjects
A page holds one optional main Subject and an ordered list of other Subjects. These endpoints create Subjects and arrange them.
| Endpoint | Description |
|---|---|
GET /neowiki | List all of the page's Subjects. expand with schemas or relations. |
GET /neowiki | Fetch the page's main Subject. Returns {pageId, subject}, the Subject carrying its page fields; subject is null when the page has none. |
GET /neowiki | List the notices to show before editing the page's Subjects, in display order. Optional schema adds notices scoped to that Schema. Returns {notices: [{key, html}]}. See Edit notices. |
GET /neowiki | Export the page's Subjects and metadata as RDF. For format and projection, see RDF export. |
POST /neowiki | Create the page's main Subject. See Creating Subjects. |
PUT /neowiki | Promote one of the page's other Subjects to main, or clear it. |
POST /neowiki | Create one of the page's other Subjects. See Creating Subjects. |
PUT /neowiki | Reorder the page's other Subjects and set the main Subject. |
Schemas
A Schema defines a Subject type and its properties. For the body shape, see Schema format.
| Endpoint | Description |
|---|---|
GET /neowiki | List Schemas. Cursor-paginated with limit and cursor. |
GET /neowiki | Fetch a Schema by name. |
PUT /neowiki | Create or replace a Schema: 201 for a new one, 200 for a replaced one. For the body, see Schema format. |
DELETE /neowiki | Delete a Schema, even one that Subjects still use: 200, 202 when the deletion completes later, or 404 when there is none. Optional body comment, logged as the deletion reason. |
GET /neowiki | Fetch a Schema as a JSON Schema document describing its Subjects. |
GET /neowiki | Find Schema names by prefix. |
Layouts
A Layout defines how a Subject is displayed. To create, change, or delete one, use MediaWiki's Action API on the page Layout:<name>: action=edit, action=delete.
| Endpoint | Description |
|---|---|
GET /neowiki | List Layouts. Cursor-paginated with limit and cursor. |
GET /neowiki | Fetch a Layout by name. |
Mappings
An ontology Mapping defines one projection: it projects native Schemas into a target ontology. For the format and concepts, see Mapping Format. To create, change, or delete one, use MediaWiki's Action API on the page Mapping:<name>: action=edit, action=delete.
| Endpoint | Description |
|---|---|
GET /neowiki | List ontology Mappings, each with the names of its mapped Schemas. Cursor-paginated with limit and cursor. |
Query
| Endpoint | Description |
|---|---|
POST /neowiki | Run a read-only Cypher query against the graph. See Query API. |
Graph stores
Report and rebuild the graph stores this wiki projects into. A rebuild's 202 means filed, not started: poll the GET until activeRun clears. See Background rebuilds.
| Endpoint | Description |
|---|---|
GET /neowiki | Report every configured store: its projection, its state (in-sync, stale or never-built), its activeRun, and the processed/failed counts of its lastSuccessfulRun. |
POST /neowiki | Queue a rebuild of one store. 202 with the run; 409 when one is already active. |
DELETE /neowiki | Cancel the rebuild a store has queued or running. 200 with the cancelled run; 404 when it has none, and when no such store is configured. |
Permissions
Where the wiki itself requires login to read, every endpoint answers an anonymous request with 403 and "error": "rest-read-denied", before any of the per-page rules below apply.
The Subject, Subject list, recently-edited-subjects, page-subjects, main-subject, edit-notices, subject-labels, referencing-subjects, Schema, Layout, Mapping, RDF export, and entity-dereference read endpoints enforce the caller's per-page read permission; page protection and $wgNamespaceProtection do not restrict them, because MediaWiki's read action ignores both. When you may not read a page they respond as if the data were absent — a null value, an empty list, or a 404 — never a 403. GET /subject-labels, GET /subjects, GET /recently-edited-subjects, and GET /subject/{subjectId}/referencingSubjects omit rows whose page you cannot read; because that filter runs per result, all cap limit at 50. A GET /subjects request reads at most 1,000 Subjects looking for ones you may read; on reaching that cap it ends the listing with a null nextCursor.
GET /subject-counts is gated by the neowiki-query right instead of per-page read: its counts include Subjects on pages you may not read. Without the right it answers 403.
The GET /schemas, GET /layouts, and GET /mappings list endpoints paginate with an opaque cursor over the rows you may read (see Cursor pagination): a restricted Schema, Layout, or Mapping is skipped exactly like one that does not exist, and no total count is reported, so nothing about restricted rows can be inferred from the pagination.
Subject write endpoints require per-page edit permission and answer 403 when you may read the page but not edit it. Denial of read answers 404 instead, so that a page you may not read stays indistinguishable from one that is absent. The write endpoints keyed by page id (Pages and Subjects) return that 404 for a page you may not read and for a page id that does not exist; the write endpoints keyed by Subject id return it for a Subject on a page you may not read and for a Subject id that does not exist. POST /neowiki/v0/subjects is keyed by a title you supply rather than by an existing page: it answers 403 for a title you may not create, and 409 for one already taken, carrying that title and nothing about the page holding it.
The Schema write endpoints need the same permissions as creating, editing, or deleting the Schema's page in the wiki. They answer 403 when you may read that page but not make the change, and 404 when you may not read it.
The Cypher query endpoint is gated only by the neowiki-query right, with no per-page filtering (see Query API).
The graph-store endpoints are gated by the neowiki-admin right.
Cursor pagination
The Schema, Layout, Mapping, and Subject list endpoints paginate with an opaque cursor. Request up to limit items (1–50, default 10); the response carries the items and a nextCursor:
{ "schemas": [ ... ], "nextCursor": "1462" }Pass that value back as cursor to fetch the next page; null marks the last page or, on a Subject list, an early end. Do not construct a cursor yourself — a malformed one is rejected with a 400. Cursors stay valid while items are created and deleted.
The expand parameter
The Subject read and page-subjects read endpoints take an optional multi-valued expand query parameter (pipe-separated, e.g. ?expand=schemas|relations) that embeds related data in the response. On the Subject read, page adds the page fields described in Subject format to each returned Subject. On the page-subjects read, schemas adds a top-level schemas map from Schema name to the Schema format body of every Schema the returned Subjects use. Both endpoints accept relations, which shapes the response differently on each endpoint. Per-Subject objects follow Subject format — page fields are trimmed from the examples below.
expand=relations resolves every relation-type Statement value (each holds a target Subject ID) to the full target Subject; match a relation value's target against the resolved Subjects to look one up. A target that does not resolve to a Subject you can read is silently omitted — the relation value itself is unchanged.
On the Subject read, the targets are merged into the same subjects map as the requested Subject, which requestedId identifies, and so are the targets of each Dependent Subject among them, in turn:
{
"requestedId": "sEpfwJLnxyQy6vR",
"subjects": {
"sEpfwJLnxyQy6vR": {
"id": "sEpfwJLnxyQy6vR",
"label": "Rijksmuseum",
"displayName": "Rijksmuseum",
"displayNameIsGenerated": false,
"schema": "Museum",
"statements": {
"City": { "propertyType": "relation", "value": [ { "id": "rEpfwJLoEB5UuQS", "target": "sEpfwJLnuwcxvuJ" } ] }
}
},
"sEpfwJLnuwcxvuJ": { "id": "sEpfwJLnuwcxvuJ", "label": "Amsterdam", "displayName": "Amsterdam", "displayNameIsGenerated": false, "schema": "City", "statements": { ... } }
}
}On the page-subjects read, the page's own Subjects stay in subjects and the resolved targets go in a separate top-level referencedSubjects map keyed by Subject ID:
{
"pageId": 93,
"mainSubjectId": "sEpfwJLnxyQy6vR",
"subjects": {
"sEpfwJLnxyQy6vR": { "id": "sEpfwJLnxyQy6vR", "label": "Rijksmuseum", "displayName": "Rijksmuseum", "displayNameIsGenerated": false, "schema": "Museum", "statements": { ... } },
"sEpfwJLAtndAaaA": { "id": "sEpfwJLAtndAaaA", "label": null, "displayName": "Attendance", "displayNameIsGenerated": true, "schema": "Attendance", "hostSubject": { "id": "sEpfwJLnxyQy6vR", "displayName": "Rijksmuseum", "displayNameIsGenerated": false, "schema": "Museum" }, "statements": { ... } }
},
"referencedSubjects": {
"sEpfwJLnuwcxvuJ": { "id": "sEpfwJLnuwcxvuJ", "label": "Amsterdam", "displayName": "Amsterdam", "displayNameIsGenerated": false, "schema": "City", "statements": { ... } }
}
}A target already among the page's own Subjects (a relation to another Subject on the same page) is not repeated in referencedSubjects. When relations is requested but nothing resolves, referencedSubjects is an empty array ([]).
Full specification
The OpenAPI 3.0 description carries every endpoint's parameters, request bodies, and responses. Browse it live on the demo wiki: neowiki.dev/w/rest.php/specs/v0/module/-. Paste that JSON into editor.swagger.io or any OpenAPI viewer. On your own wiki, register the spec routes first — $wgRestAPIAdditionalRouteFiles[] = 'includes/Rest/specs.v0.json'; in LocalSettings.php — then fetch /rest.php/specs/v0/module/-.