Content Module
June 17, 2026 · 5 min read
The Content Module is a CMS-like module for MedusaJS that allows creating and managing content pages like blog articles, landing pages, product descriptions and anything else that you might want to manage as content.
#Admin Dashboard Usage
After installing the plugin, the "Content" section will become available in the admin sidebar.
#Rich Text Editor
Content editing is done through a rich text editor via the lexical editor library. The editor supports all Markdown features.
#Admin API
#Query Content Posts
GET /admin/blog/posts - Query content posts with optional filters, sorting, and pagination.
Query parameters:
offset- Number of posts to skip (default: 0)limit- Maximum number of posts to return (default: 20)order- Sort order of the posts (default: "created_at DESC")published- Filter by published status (true/false)q- Search query for post title or contentpost_type_id- Filter by post type ID
#Get Single Post
GET /admin/blog/posts/:id - Retrieve a single content post by its ID.
#Create Post
POST /admin/blog/posts - Create a new content post.
Request body:
title(string, required) - Title of the post.slug(string, required) - URL-friendly slug for the post.content(string, required) - The post content (supports Markdown).featured_image(string, optional, nullable) - URL of the featured image.published(boolean, required) - Whether the post is published.post_type_id(string, optional, nullable) - ID of the post type.tags(array of strings, required) - List of tag IDs to associate.categories(array of strings, required) - List of category IDs to associate.metadata(record, optional, nullable) - Custom key-value metadata.
#Update Post
PUT /admin/blog/posts/:id - Update an existing content post.
Request body (all fields optional):
title(string) - Title of the post.slug(string) - URL-friendly slug for the post.excerpt(string, optional, nullable) - Short excerpt/summary of the post.content(string) - The post content (supports Markdown).featured_image(string, optional, nullable) - URL of the featured image (must be a valid URL).published(boolean) - Whether the post is published.published_at(string, optional, nullable) - ISO 8601 datetime of publication.metadata(record, optional, nullable) - Custom key-value metadata.post_type_id(string, optional, nullable) - ID of the post type.categories(array of strings) - List of category IDs to associate.tags(array of strings) - List of tag IDs to associate.
#Delete Post
DELETE /admin/blog/posts/:id - Delete a content post.
#List Categories
GET /admin/blog/categories - Query categories with optional pagination.
Query parameters:
offset- Number of categories to skip (default: 0)limit- Maximum number of categories to return (default: 20)q- Search query for category nameorder- Sort order (default: "created_at DESC")
#Get Single Category
GET /admin/blog/categories/:id - Retrieve a single category by its ID.
#Create Category
POST /admin/blog/categories - Create a new category.
Request body:
name(string, required) - Name of the category.slug(string, required) - URL-friendly slug for the category.description(string, optional, nullable) - Description of the category.
#Update Category
PUT /admin/blog/categories/:id - Update an existing category.
Request body (all fields optional):
name(string) - Name of the category.slug(string) - URL-friendly slug for the category.description(string, optional, nullable) - Description of the category.
#Delete Category
DELETE /admin/blog/categories/:id - Delete a category.
#List Tags
GET /admin/blog/tags - Query tags with optional pagination.
Query parameters:
offset- Number of tags to skip (default: 0)limit- Maximum number of tags to return (default: 20)q- Search query for tag nameorder- Sort order (default: "created_at DESC")
#Get Single Tag
GET /admin/blog/tags/:id - Retrieve a single tag by its ID.
#Create Tag
POST /admin/blog/tags - Create a new tag.
Request body:
name(string, required) - Name of the tag.slug(string, required) - URL-friendly slug for the tag.
#Update Tag
PUT /admin/blog/tags/:id - Update an existing tag.
Request body (all fields optional):
name(string) - Name of the tag.slug(string) - URL-friendly slug for the tag.
#Delete Tag
DELETE /admin/blog/tags/:id - Delete a tag.
#List Post Types
GET /admin/blog/post-types - Query post types with optional pagination.
Query parameters:
offset- Number of post types to skip (default: 0)limit- Maximum number of post types to return (default: 20)q- Search query for post type nameorder- Sort order (default: "created_at DESC")
#Get Single Post Type
GET /admin/blog/post-types/:id - Retrieve a single post type by its ID.
#Create Post Type
POST /admin/blog/post-types - Create a new post type.
Request body:
name(string, required) - Name of the post type.slug(string, required) - URL-friendly slug for the post type.description(string, optional, nullable) - Description of the post type.
#Update Post Type
PUT /admin/blog/post-types/:id - Update an existing post type.
Request body (all fields optional):
name(string) - Name of the post type.slug(string) - URL-friendly slug for the post type.description(string, optional, nullable) - Description of the post type.
#Delete Post Type
DELETE /admin/blog/post-types/:id - Delete a post type.
#Store API
Store API routes are public-facing and read-only. They return only published content.
#Posts
#List Posts
GET /store/blog/posts - Query published content posts with optional filters, sorting, and pagination.
Query parameters:
offset- Number of posts to skip (default: 0)limit- Maximum number of posts to return (default: 20)order- Sort order (default: "created_at DESC")q- Search query for post title or contentpost_type_id- Filter by post type ID
#Get Single Post
GET /store/blog/posts/:id - Retrieve a single published content post by its ID.
#Categories
#List Categories
GET /store/blog/categories - Query categories with optional pagination.
Query parameters:
offset- Number of categories to skip (default: 0)limit- Maximum number of categories to return (default: 20)q- Search query for category nameorder- Sort order (default: "created_at DESC")
#Get Single Category
GET /store/blog/categories/:id - Retrieve a single category by its ID.
#Tags
#List Tags
GET /store/blog/tags - Query tags with optional pagination.
Query parameters:
offset- Number of tags to skip (default: 0)limit- Maximum number of tags to return (default: 20)q- Search query for tag nameorder- Sort order (default: "created_at DESC")
#Get Single Tag
GET /store/blog/tags/:id - Retrieve a single tag by its ID.
#Post Types
#List Post Types
GET /store/blog/post-types - Query post types with optional pagination.
Query parameters:
offset- Number of post types to skip (default: 0)limit- Maximum number of post types to return (default: 20)q- Search query for post type nameorder- Sort order (default: "created_at DESC")
#Get Single Post Type
GET /store/blog/post-types/:id - Retrieve a single post type by its ID.