Skip to main content

Overview

The Blog API provides comprehensive content management endpoints for articles, authors, categories, comments, and media. All Blog API endpoints require admin authentication.

Articles

List Articles

curl "https://your-domain.com/api/admin/blog/articles?page=1&perPage=20&status=published" \
  -H "Authorization: Bearer <token>"

Query Parameters

page
integer
default:"1"
Page number (1-indexed)
perPage
integer
default:"20"
Items per page (max: 100)
q
string
Search by slug
status
string
Filter by status: draft, published, scheduled, archived
Filter featured articles (true or false)
home
boolean
Filter articles displayed on homepage
blog
boolean
Filter articles displayed in blog listing
category
string
Filter by category ID
organizationId
string
Filter by organization ID
id
string
Fetch single article by ID (returns full details with translations, authors, categories, media)

Create Article

From /src/pages/api/admin/blog/articles.ts:197-297:
curl -X POST "https://your-domain.com/api/admin/blog/articles" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d @article.json

Request Body

action
string
required
Must be "create"
slug
string
required
URL-friendly slug (auto-generated if not provided)
status
string
default:"draft"
Article status: draft, published, scheduled, archived
inLanguage
string
default:"fr"
Primary language code (ISO 639-1)
organizationId
string
Organization ID (nullable)
displayInHome
boolean
default:"false"
Show on homepage
displayInBlog
boolean
default:"true"
Show in blog listing
Mark as featured
allowComments
boolean
default:"true"
Enable comments
readingTime
string
Estimated reading time (e.g., “5 min”)
wordCount
string
Article word count
translations
array
Array of translation objects (see structure above)
authorIds
string[]
Array of author IDs
categoryIds
string[]
Array of category IDs
media
array
Array of media objects with mediaId, type, position

Update Article

From /src/pages/api/admin/blog/articles.ts:299-409:
{
  "action": "update",
  "id": "art_456",
  "slug": "updated-slug",
  "status": "published",
  "isFeatured": true,
  "translations": [...],
  "authorIds": [...],
  "categoryIds": [...]
}
Updating an article replaces translations, authors, categories, and media (full replacement strategy).

Other Article Actions

From /src/pages/api/admin/blog/articles.ts:411-534:

Publish Article

{
  "action": "publish",
  "id": "art_456"
}
Sets status to "published" and sets publishedAt to current timestamp.

Unpublish Article

{
  "action": "unpublish",
  "id": "art_456"
}

Delete Article

{
  "action": "delete",
  "id": "art_456"
}
Deletes the article and all related data (translations, authors, categories, media).

Duplicate Article

{
  "action": "duplicate",
  "id": "art_456"
}
Creates a copy with status "draft" and unique slug.

Authors

List Authors

From /src/pages/api/admin/blog/authors.ts:19-98:
GET /api/admin/blog/authors?page=1&perPage=20

Query Parameters

id
string
Fetch single author by ID (includes article count)
all
boolean
Return all authors (for selectors) with minimal fields
q
string
Search by slug
Filter featured authors
home
boolean
Filter authors displayed on homepage
blog
boolean
Filter authors displayed in blog

Create Author

From /src/pages/api/admin/blog/authors.ts:122-166:
{
  "action": "create",
  "slug": "john-doe",
  "displayName": { "fr": "John Doe", "en": "John Doe" },
  "givenName": { "fr": "John" },
  "familyName": { "fr": "Doe" },
  "bio": { "fr": "Auteur passionné" },
  "jobTitle": { "fr": "Journaliste" },
  "email": "john@example.com",
  "avatarUrl": "https://example.com/avatar.jpg",
  "website": "https://johndoe.com",
  "displayInHome": false,
  "displayInBlog": true,
  "isFeatured": false
}

Response

{
  "ok": true,
  "id": "author_789",
  "slug": "john-doe"
}

Update/Delete Author

From /src/pages/api/admin/blog/authors.ts:168-238:
// Update
{ "action": "update", "id": "author_789", "displayName": {...} }

// Delete
{ "action": "delete", "id": "author_789" }

Categories

List Categories

From /src/pages/api/admin/blog/categories.ts:18-102:
GET /api/admin/blog/categories?all=true

Query Parameters

id
string
Fetch single category by ID
all
boolean
Return all categories (for selectors)
parent
string
Filter by parent ID (use "root" for top-level)
menu
boolean
Filter categories shown in menu

Create Category

From /src/pages/api/admin/blog/categories.ts:126-165:
{
  "action": "create",
  "slug": "tech",
  "name": { "fr": "Technologie", "en": "Technology" },
  "description": { "fr": "Articles sur la technologie" },
  "parentId": null,
  "displayInHome": true,
  "displayInMenu": true,
  "displayInBlog": true,
  "isFeatured": false
}

Comments

List Comments

From /src/pages/api/admin/blog/comments.ts:13-66:
GET /api/admin/blog/comments?status=pending&page=1

Query Parameters

status
string
Filter by status: pending, approved, rejected
type
string
Filter by post type
q
string
Search by author name or email

Response

{
  "comments": [...],
  "total": 42,
  "page": 1,
  "perPage": 25,
  "totalPages": 2,
  "stats": {
    "pending": 12,
    "approved": 28,
    "rejected": 2
  }
}

Moderate Comments

From /src/pages/api/admin/blog/comments.ts:72-162:
{
  "action": "approve",
  "id": "comment_123"
}

Media

List Media

From /src/pages/api/admin/blog/media.ts:20-51:
GET /api/admin/blog/media?type=image&page=1&perPage=30

Query Parameters

type
string
Filter by media type: image, video, audio
q
string
Search by URL

Upload Media

From /src/pages/api/admin/blog/media.ts:57-210:
curl -X POST "https://your-domain.com/api/admin/blog/media" \
  -H "Authorization: Bearer <token>" \
  -F "file=@image.jpg" \
  -F "alt=Image description" \
  -F "caption=Photo caption" \
  -F "customName=my-image"

Configuration

  • Upload directory: public/uploads/blog
  • Max file size: 10 MB
  • Allowed types: JPEG, PNG, WebP, AVIF, GIF, SVG

Form Fields

file
File
required
Image file to upload
customName
string
Custom filename (auto-sanitized)
alt
string
Alt text for accessibility
caption
string
Image caption
description
string
Detailed description

Update/Delete Media

From /src/pages/api/admin/blog/media.ts:66-115:
{
  "action": "update",
  "id": "media_999",
  "caption": { "fr": "Nouvelle légende" },
  "alt": { "fr": "Nouveau texte alternatif" }
}
Deleting media also removes the file from disk.

Common Response Codes

CodeDescription
200Success
201Created
400Invalid request (missing fields, invalid action)
403Not admin (forbidden)
404Resource not found
500Server error

Audit Logging

All Blog API actions are logged to audit_log table:
  • blog.article.create
  • blog.article.update
  • blog.article.delete
  • blog.article.publish
  • blog.article.unpublish
  • blog.article.duplicate
  • blog.author.create
  • blog.author.update
  • blog.author.delete
  • blog.category.create
  • blog.category.update
  • blog.category.delete
  • blog.comment.approve
  • blog.comment.reject
  • blog.comment.delete
  • blog.media.upload
  • blog.media.delete

API Overview

Authentication and rate limiting

Services API

Manage service listings