Skip to main content

Blogs

Blog posts are the primary content type in Forja. They support localization, categories, editorial workflow, document attachments, and RSS feeds.

Endpoints

MethodPathPermissionDescription
GET/sites/{site_id}/blogs?page&per_pageblog:readList all blogs (paginated)
GET/sites/{site_id}/blogs/published?page&per_pageblog:readList published blogs
GET/sites/{site_id}/blogs/featured?limitblog:readList featured blogs
GET/sites/{site_id}/blogs/{id}/similar?limitblog:readList similar blogs by taxonomy overlap
GET/sites/{site_id}/blogs/by-slug/{slug}blog:readGet blog by slug
GET/blogs/{id}blog:readGet blog by ID
GET/blogs/{id}/detailblog:readGet blog with localizations, categories, and documents
POST/blogsblog:createCreate a blog post
PUT/blogs/{id}blog:update:own / blog:update:anyUpdate a blog post (ownership enforced)
DELETE/blogs/{id}blog:delete:own / blog:delete:anySoft delete a blog post (ownership enforced)
POST/blogs/{id}/cloneblog:createClone a blog as a new Draft
POST/blogs/{id}/reviewblog:reviewApprove or request changes
GET/blogs/{id}/localizationsblog:readGet all localizations
POST/blogs/{id}/localizationsblog:createCreate a localization
PUT/blogs/localizations/{loc_id}blog:updateUpdate a localization
DELETE/blogs/localizations/{loc_id}blog:deleteDelete a localization
GET/sites/{site_id}/feed.rssblog:readRSS 2.0 feed of published posts
POST/sites/{site_id}/blogs/bulkblog:update / blog:deleteBulk status update or delete
POST/sites/{site_id}/blogs/seedblog:createSeed sample blog content
DELETE/sites/{site_id}/blogs/samplesblog:deleteDelete sample blog content

Ownership enforcement: Update and delete operations check resource ownership. Authors (with blog:update:own) can only modify their own content. Editors+ (with blog:update:any) can modify any content. Published content requires blog:update:published (Editor+).

Slug auto-generation: The slug field in POST /blogs is now optional. If omitted, a slug is auto-generated from the title field using Unicode transliteration with uniqueness enforcement (appends -2, -3 on collision).

List Blogs

curl -H "X-API-Key: oy_live_abc123..." \
"https://your-domain.com/api/v1/sites/{site_id}/blogs?page=1&per_page=10"

Response 200 OK -- Paginated list with data and meta fields.

List Published Blogs

The published blogs endpoint (/sites/{site_id}/blogs/published) supports an optional locale_id query parameter:

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
per_pageintegerNoItems per page (default: 10)
locale_idUUIDNoFilter to blogs that have content in the specified locale. When provided, only blogs with a localization matching this locale are returned, and pagination counts (total, total_pages) reflect the filtered set.
curl -H "X-API-Key: oy_live_abc123..." \
"https://your-domain.com/api/v1/sites/{site_id}/blogs/published?page=1&per_page=10&locale_id=550e8400-..."

Get Blog Detail

Returns the blog post with all localizations, assigned categories, and attached documents in a single response.

curl -H "X-API-Key: oy_live_abc123..." \
https://your-domain.com/api/v1/blogs/{id}/detail

Create a Blog

curl -X POST \
-H "X-API-Key: oy_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"site_ids": ["550e8400-..."],
"slug": "my-first-post",
"author": "John Doe",
"status": "Draft"
}' \
https://your-domain.com/api/v1/blogs

Response 201 Created

Similar Blogs

Returns blogs similar to the given blog post, ranked by taxonomy overlap. Scoring: shared tags (+3 each), shared categories (+2 each), primary category match (+3 bonus), same author (+1). Only published blogs with a score > 0 are returned. If nothing is similar, the response is an empty array.

curl -H "X-API-Key: oy_live_abc123..." \
"https://your-domain.com/api/v1/sites/{site_id}/blogs/{id}/similar?limit=3"

Query Parameters

ParameterDefaultMaxDescription
limit310Number of similar blogs to return

Response 200 OK -- Array of BlogListItem objects sorted by relevance score (descending), then by published_date (most recent first).

Editorial Workflow

Content follows the lifecycle: Draft -> InReview -> Published (or Scheduled). Submitting content for review notifies reviewers. Reviewers can approve (moves to Published/Scheduled) or request changes (moves back to Draft).

curl -X POST \
-H "X-API-Key: oy_live_abc123..." \
-H "Content-Type: application/json" \
-d '{"action": "Approve"}' \
https://your-domain.com/api/v1/blogs/{id}/review

RSS Feed

Returns an RSS 2.0 XML feed of the last 50 published blog posts. The response has Content-Type: application/rss+xml and is cached for 1 hour.

curl -H "X-API-Key: oy_live_abc123..." \
https://your-domain.com/api/v1/sites/{site_id}/feed.rss

Bulk Actions

Perform bulk status updates or deletes on multiple blogs at once. Delete requires Editor role; status update requires Author role.

curl -X POST \
-H "X-API-Key: oy_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"action": "UpdateStatus",
"ids": ["id1", "id2"],
"status": "Published"
}' \
https://your-domain.com/api/v1/sites/{site_id}/blogs/bulk

Seed Sample Content

Creates 3 sample draft blog posts for a new site, marked as samples. Useful for onboarding so new sites are not empty. Returns 400 if sample content already exists.

curl -X POST \
-H "X-API-Key: oy_live_abc123..." \
https://your-domain.com/api/v1/sites/{site_id}/blogs/seed

Response 201 Created -- Returns an array of the created BlogResponse objects.

Delete Sample Content

Deletes all blog posts marked as sample content for a site. Requires Editor role.

curl -X DELETE \
-H "X-API-Key: oy_live_abc123..." \
https://your-domain.com/api/v1/sites/{site_id}/blogs/samples

Response 200 OK

{
"deleted": 3
}