The blog adds four resources to Omeka Classic's REST API: blog_posts, blog_categories, blog_tags and blog_comments. They follow Omeka's conventions: JSON, page and per_page, sort_field and sort_dir, the Omeka-Total-Results and Link headers, and API keys in the key parameter. The API must be turned on under Settings > API. When the API Browser plugin is installed, the four resources appear in it with their parameters and fields.
Create a key under Users > (user) > API Keys and add it to each request:
https://example.org/api/blog_posts?key=YOUR_KEY
Who sees and does what
A request without a key is a visitor. A key acts as its user, with the blog's rules (see Configuration):
| Resource | Read | Create | Update | Delete |
|---|---|---|---|---|
blog_posts |
everyone: published posts only; Contributors' keys also their own; Admins', Super Users' and Researchers' keys everything | Contributors (their posts go to review), Admins, Super Users | the author (a Contributor) or Admins and Super Users | Admins, Super Users |
blog_categories |
everyone | Admins, Super Users | Admins, Super Users | Admins, Super Users |
blog_tags |
everyone | not available | not available | not available |
blog_comments |
everyone: approved comments on published posts, without email addresses; Admins' and Super Users' keys everything | everyone (a pending comment) | Admins, Super Users (the status) | Admins, Super Users |
A record the key may not see answers 404, as if it did not exist; an action it may not take answers 403.
Posts: /api/blog_posts
GET /api/blog_posts lists posts, newest first.
| Parameter | Description |
|---|---|
status |
draft, pending, published, scheduled (published, date to come) or live (published, date passed). Keys that see only published posts get live posts whatever they ask. |
category |
Category ID. |
category_slug |
Category address. |
tag |
Tag address. |
author |
User ID. |
search |
Words in the title, excerpt or text (each word must match). |
exclude_future |
1 leaves out scheduled posts. |
slug |
The post with this address. |
sort_field |
published (the default order), title, modified, added or id, with sort_dir a or d. |
GET /api/blog_posts/{id}:
{
"id": 3,
"url": "https://example.org/api/blog_posts/3",
"title": "From the Archive: Ruth Calder at the Mill Gate",
"slug": "from-the-archive-ruth-calder-at-the-mill-gate",
"excerpt": "Calder held her camera at waist height…",
"content": "<p>Among Ruth Calder’s papers is a ledger…</p>",
"status": "published",
"scheduled": false,
"published": "2026-10-02T14:00:00+00:00",
"public_url": "https://example.org/blog/from-the-archive-ruth-calder-at-the-mill-gate",
"author": {"id": 18, "name": "Desmond Hale", "url": "https://example.org/api/users/18", "resource": "users"},
"category": {"id": 3, "name": "From the Archive", "slug": "from-the-archive", "url": "https://example.org/api/blog_categories/3", "resource": "blog_categories"},
"tags": [{"id": 5, "name": "photographs", "slug": "photographs", "url": "https://example.org/api/blog_tags/5", "resource": "blog_tags"}],
"featured_image": {"url": "https://example.org/files/fullsize/6f76….jpg", "file": {"id": 38, "url": "https://example.org/api/files/38", "resource": "files"}},
"featured_image_url": null,
"comments": {"count": 2, "url": "https://example.org/api/blog_comments?post=3", "resource": "blog_comments"},
"added": "2026-10-02T14:00:00+00:00",
"modified": "2026-10-02T14:00:00+00:00",
"extended_resources": []
}
Dates are in UTC (ISO 8601). comments.count counts approved comments, or all of them for moderators' keys.
POST /api/blog_posts creates a post; the key's user is its author. PUT /api/blog_posts/{id} changes only the keys sent.
| Key | Description |
|---|---|
title |
Required for a new post. |
slug |
Its address; made from the title when empty. |
excerpt, content |
HTML, filtered as the post form is. |
status |
draft (default), pending or published. A Contributor's published becomes pending. |
published |
Publication date (ISO 8601, or YYYY-MM-DD HH:MM); a future date schedules the post. Empty with published status: now. |
category |
Category ID (or {"id": 3}). The API does not require one; the post form does. |
tags |
Tag names (or {"name": …} objects); new ones are made. Replaces the post's tags. |
featured_file |
ID of a file with an image, or null. |
featured_image_url |
An image address, used without a file. |
curl -X POST "https://example.org/api/blog_posts?key=YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Hello","content":"<p>World</p>","status":"published","category":1,"tags":["news"]}'
A post that does not validate answers 400 with the problems, such as {"message":"Error when saving record.","errors":{"slug":"Another post already has the slug \"hello\"."}}.
DELETE /api/blog_posts/{id} deletes the post and its comments (204).
Categories: /api/blog_categories
GET /api/blog_categories(by name;slugandnamefilter) andGET /api/blog_categories/{id}:id,name,slug,description,public_url, andposts(count, the posts the key may see, andurl).POSTwithname(required),sluganddescription;PUTwith any of them.DELETEkeeps the posts, without a category.
Tags: /api/blog_tags
Read only. GET /api/blog_tags (by name; slug, name (contains) and post (a post's ID) filter) and GET /api/blog_tags/{id}: id, name, slug, public_url and posts. Tags are made with posts.
Comments: /api/blog_comments
GET /api/blog_comments, newest first, with status (pending, approved, spam; moderators' keys), post (a post's ID) and search. Each comment has id, post, author_name, body, status, added, and author_email for moderators' keys only.
POST /api/blog_comments sends a comment to a published post, with or without a key:
curl -X POST https://example.org/api/blog_comments \
-H "Content-Type: application/json" \
-d '{"post":3,"author_name":"Walt Brenner","author_email":"walt@example.org","body":"My father worked the second shift."}'
It is pending, the moderators are emailed, and the answer (201) shows it. The same checks as the form apply, but for the hidden field and the form token: 403 when comments are off, 429 after the hourly limit per address, Spam beyond the links allowed, 400 for missing or invalid fields or a post that is not published. Moderators' keys may give a status.
PUT /api/blog_comments/{id} moderates: {"status":"approved"}, "spam" or "pending"; other keys are ignored. DELETE removes the comment.