The module exposes a small JSON API under /api/page-versioning/. It is separate from Omeka's core /api endpoint and is aimed at scripts and integrations that need to read history or trigger a revert.
Authentication
These routes are not part of Omeka's core API route, so the key_identity and key_credential API key parameters are not recognised. Requests are authenticated with the normal Omeka S login session: call the endpoints from a browser that is logged in to the admin panel, or send the session cookie from your script.
Permissions are those of the history screens in the admin panel:
| Endpoint | Rule |
|---|---|
| List versions | Author role or higher, otherwise 403. The page must also be readable by the requester; private pages return 404 to users who cannot see them |
| Get a version | Author role or higher, otherwise 403 |
| Revert | Editor role or higher, otherwise 403. Omeka must also let the user change that page (a 403 otherwise) |
Requests without a login session get a 403.
Response format
Successful responses:
{ "status": "ok", "data": { ... } }
Errors use an HTTP status code and this body:
{ "status": "error", "message": "Version #12 not found" }
Every response, error or not, is JSON with the content type application/json.
| Status | Meaning |
|---|---|
| 400 | Invalid ID, a JSON body that is not an object, or a summary that is not text |
| 403 | The user's role may not use the endpoint, or may not change the page |
| 404 | The page or version does not exist, or the page is not visible to the user |
| 405 | Wrong HTTP method |
| 422 | Omeka refused to save the page as it was in the version; see below |
| 500 | An unexpected error; the message says what failed and the error is written to Omeka's log |
A revert that Omeka's validation refuses, typically because another page of the site now uses the version's slug, returns 422 with the reasons by field, as Omeka's own API does:
{
"status": "error",
"message": "The slug \"about\" is already taken.",
"errors": { "o:slug": ["The slug \"about\" is already taken."] }
}
The page and its history are left as they were. Give the other page a different slug and try again.
List versions for a page
GET /api/page-versioning/{pageId}/versions
| Query parameter | Default | Description |
|---|---|---|
limit |
50 | Number of versions to return, 1 to 200 |
offset |
0 | Number of versions to skip |
type |
site_page |
Resource type filter; only site_page is written by this module |
Versions are returned newest first without their payload:
{
"status": "ok",
"data": {
"resource_id": 42,
"resource_type": "site_page",
"total": 12,
"limit": 50,
"offset": 0,
"versions": [
{
"id": "99",
"resource_id": "42",
"resource_type": "site_page",
"title": "About the collection",
"slug": "about",
"operation": "update",
"editor_id": "3",
"editor_name": "Jane Doe",
"summary": null,
"created_at": "2026-03-15 14:30:00"
}
]
}
}
Numeric columns may be returned as strings, depending on the database driver.
Get a single version
GET /api/page-versioning/version/{versionId}
Returns the full row including the decoded payload (title, slug, is_public, layout, layout_data, blocks and site_id). The structure is the same as the JSON export described in Exporting and Deleting Versions.
Revert a page to a version
POST /api/page-versioning/version/{versionId}/revert
Content-Type: application/json
{ "summary": "Restoring the introduction paragraph" }
The body may be JSON or form encoded. summary is optional; when omitted the revert entry is noted as "Reverted to version #N (saved ...)". The response contains the ID of the new revert version:
{ "status": "ok", "data": { "new_version_id": 103 } }
The revert behaves exactly like a revert from the admin interface; see Reverting a Page.
Example
# Using a browser session cookie exported from the admin panel
curl -s -b "PHPSESSID=..." \
"https://example.org/api/page-versioning/42/versions?limit=5" | python3 -m json.tool
Developer notes
- Version capture is attached to the
entity.persist.postandentity.update.postevents forOmeka\Entity\SitePageandOmeka\Entity\SitePageBlock. Any save that goes through Omeka's entity manager is captured; direct SQL changes are not. - The service
PageVersioning\Service\VersionManageris available from the service manager and provideslistVersions(),getVersion(),diff(),revertToVersion(),deleteVersion()andcaptureFromPayload(). - Versions are stored in the
page_versionstable with raw DBAL queries; there is no Doctrine entity.