Early developmentNot everything described here has shipped yet.

Skip to content

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.

EndpointDescription
GET /neowiki/v0/subject/{subjectId}Fetch a Subject as the wiki publishes it, or at another revision. See Reading Subjects.
GET /neowiki/v0/subject/{subjectId}/rdfExport one Subject as RDF. For format and projection, see RDF export.
GET /neowiki/v0/entity/{subjectId}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/v0/subject/{subjectId}Replace a Subject's label and statements.
DELETE /neowiki/v0/subject/{subjectId}Delete a Subject.
POST /neowiki/v0/subject/{subjectId}/moveMove 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/v0/subject/{subjectId}/statements/{propertyName}Set one Statement, leaving the Subject's label and other Statements as they are.
DELETE /neowiki/v0/subject/{subjectId}/statements/{propertyName}Remove one Statement.
POST /neowiki/v0/subject/validateCheck whether a new Subject is valid, without saving it. Returns {violations: [...]} — see Validation codes.
POST /neowiki/v0/subject/{subjectId}/validateCheck whether a change to a Subject is valid, without saving it. Returns {violations: [...]} — see Validation codes.
POST /neowiki/v0/subject-idsMint 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/v0/subjectsCreate a Subject together with a page of its own, in one revision, as that page's main Subject. See Creating Subjects.
GET /neowiki/v0/subjectsList 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/v0/recently-edited-subjectsList 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/v0/subject-countsCount 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/v0/subject-labelsFind 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/v0/subject/{subjectId}/referencingSubjectsList 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.

EndpointDescription
GET /neowiki/v0/page/{pageId}/subjectsList all of the page's Subjects. expand with schemas or relations.
GET /neowiki/v0/page/{pageId}/mainSubjectFetch the page's main Subject. Returns {pageId, subject}, the Subject carrying its page fields; subject is null when the page has none.
GET /neowiki/v0/page/{pageId}/editNoticesList 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/v0/page/{pageId}/rdfExport the page's Subjects and metadata as RDF. For format and projection, see RDF export.
POST /neowiki/v0/page/{pageId}/mainSubjectCreate the page's main Subject. See Creating Subjects.
PUT /neowiki/v0/page/{pageId}/mainSubjectPromote one of the page's other Subjects to main, or clear it.
POST /neowiki/v0/page/{pageId}/subjectsCreate one of the page's other Subjects. See Creating Subjects.
PUT /neowiki/v0/page/{pageId}/subjectsOrderingReorder 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.

EndpointDescription
GET /neowiki/v0/schemasList Schemas. Cursor-paginated with limit and cursor.
GET /neowiki/v0/schema/{schemaName}Fetch a Schema by name.
PUT /neowiki/v0/schema/{schemaName}Create or replace a Schema: 201 for a new one, 200 for a replaced one. For the body, see Schema format.
DELETE /neowiki/v0/schema/{schemaName}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/v0/schema/{schemaName}/json-schemaFetch a Schema as a JSON Schema document describing its Subjects.
GET /neowiki/v0/schema-names/{search}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.

EndpointDescription
GET /neowiki/v0/layoutsList Layouts. Cursor-paginated with limit and cursor.
GET /neowiki/v0/layout/{layoutName}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.

EndpointDescription
GET /neowiki/v0/mappingsList ontology Mappings, each with the names of its mapped Schemas. Cursor-paginated with limit and cursor.

Query ​

EndpointDescription
POST /neowiki/v0/query/cypherRun 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.

EndpointDescription
GET /neowiki/v0/graph-storesReport 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/v0/graph-stores/{name}/rebuildQueue a rebuild of one store. 202 with the run; 409 when one is already active.
DELETE /neowiki/v0/graph-stores/{name}/rebuildCancel 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:

json
{ "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:

json
{
  "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:

json
{
  "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/-.