Minolith Changelog API
The Changelog service lets you manage versioned changelogs for your project. Create entries, group them into versions, publish them, and expose a public-facing changelog page and RSS feed — all via API or MCP tools.
Base URL: https://api.minolith.io/v1/changelog
Authentication: All endpoints (except the public endpoint) require an API key via the Authorization header:
Authorization: Bearer mlth_your_api_key_here
Errors: All errors follow the standard Minolith error format. See Platform API — Error Response Format for the full specification.
Content Negotiation: All endpoints support two response formats:
Accept: application/json— JSON (default)Accept: text/markdown— Raw markdown response
Resource Shapes
Entry
{
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB. Supports automatic column mapping and duplicate detection.",
"category": "feature",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:30:00"
}
Version
{
"id": "ver_2c8e4a1b6f3d",
"name": "2.4.0",
"description": "This release focuses on data import and improved search performance.",
"status": "published",
"released_at": "2026-03-17 14:30:00",
"created_at": "2026-03-16 09:00:00",
"updated_at": "2026-03-17 14:30:00",
"entries": [
{
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "...",
"category": "feature",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:30:00"
}
]
}
The entries array is only included when fetching a single version via GET /versions/:id.
Entries
Create Entry
POST /v1/changelog/entries
Creates a new changelog entry. Costs 1 credit.
Request body:
{
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB. Supports automatic column mapping and duplicate detection.",
"category": "feature",
"status": "draft",
"version_id": "ver_2c8e4a1b6f3d"
}
| Field | Type | Required | Description |
|---|---|---|---|
title |
string | yes | Short description of the change. Max 500 characters. |
body |
string | yes | Full details. Supports markdown. Max 50,000 characters. |
category |
string | yes | One of: feature, improvement, fix, breaking, deprecation, security, other |
status |
string | no | draft or published. Defaults to draft. |
version_id |
string | no | ID of an existing version to group this entry under. Omit or set to null for ungrouped entries. |
Response (201 Created):
{
"data": {
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB. Supports automatic column mapping and duplicate detection.",
"category": "feature",
"status": "draft",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": null,
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 12:00:00"
}
}
Error responses:
422— Validation error (missing required field, invalid category, title too long, etc.)404—version_idreferences a version that does not exist in this project.402— Spending cap exceeded.
List Entries
GET /v1/changelog/entries
Returns a paginated list of entries for the authenticated project.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status: draft or published |
category |
string | Filter by category. Supports comma-separated values: category=feature,fix,breaking |
version_id |
string | Filter by version. Pass a version ID to get entries in that version, or null to get ungrouped entries. |
limit |
integer | Number of results (1-100, default 20) |
cursor |
string | Cursor from a previous response's pagination.next_cursor |
Example requests:
GET /v1/changelog/entries?status=published&category=feature,improvement&limit=50
GET /v1/changelog/entries?version_id=ver_2c8e4a1b6f3d
GET /v1/changelog/entries?version_id=null
GET /v1/changelog/entries?category=breaking,security
Response (200 OK):
{
"data": [
{
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB...",
"category": "feature",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:30:00"
},
{
"id": "ent_9d4b1e7c3a2f",
"title": "Fix timezone handling in scheduled exports",
"body": "Scheduled exports now correctly use the project timezone...",
"category": "fix",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-16 16:45:00",
"updated_at": "2026-03-17 14:30:00"
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"limit": 20
}
}
Get Entry
GET /v1/changelog/entries/:id
Returns a single entry by its ID.
Response (200 OK):
{
"data": {
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB. Supports automatic column mapping and duplicate detection.",
"category": "feature",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:30:00"
}
}
Error responses:
404— Entry not found.
{
"error": {
"code": "not_found",
"message": "Entry 'ent_nonexistent' not found.",
"docs": "https://docs.minolith.io/api/changelog#get-entry"
}
}
Update Entry
PUT /v1/changelog/entries/:id
Partially updates an existing entry. Only include the fields you want to change. Omitted fields are left unchanged. Free — no credit cost.
Request body (all fields optional):
{
"title": "Add bulk import for CSV and XLSX files",
"category": "feature",
"version_id": "ver_2c8e4a1b6f3d"
}
| Field | Type | Description |
|---|---|---|
title |
string | Max 500 characters |
body |
string | Max 50,000 characters, markdown |
category |
string | feature, improvement, fix, breaking, deprecation, security, other |
status |
string | draft or published |
version_id |
string or null | Set to a version ID to group, or null to ungroup |
Response (200 OK):
Returns the full updated entry in the same format as the create response.
Error responses:
404— Entry not found.422— Validation error.
Delete Entry
DELETE /v1/changelog/entries/:id
Permanently deletes an entry. This is a hard delete — the entry cannot be recovered. Free — no credit cost.
Response (204 No Content):
Empty response body.
Error responses:
404— Entry not found.
Publish Entry
POST /v1/changelog/entries/:id/publish
Sets the entry's status to published and published_at to the current time. Free — no credit cost.
Request body: None.
Response (200 OK):
{
"data": {
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB...",
"category": "feature",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:30:00"
}
}
Error responses:
404— Entry not found.409— Entry is already published.
{
"error": {
"code": "entry_already_published",
"message": "Entry is already published.",
"docs": "https://docs.minolith.io/api/changelog#publish-entry"
}
}
Unpublish Entry
POST /v1/changelog/entries/:id/unpublish
Reverts the entry to draft status and clears published_at. Free — no credit cost.
Request body: None.
Response (200 OK):
{
"data": {
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB...",
"category": "feature",
"status": "draft",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": null,
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:35:00"
}
}
Error responses:
404— Entry not found.409— Entry is already a draft.
{
"error": {
"code": "entry_already_draft",
"message": "Entry is already a draft.",
"docs": "https://docs.minolith.io/api/changelog#unpublish-entry"
}
}
Versions
Create Version
POST /v1/changelog/versions
Creates a new version. Costs 1 credit.
Request body:
{
"name": "2.4.0",
"description": "This release focuses on data import and improved search performance.",
"status": "draft",
"released_at": "2026-03-17T14:30:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Version name (e.g. "2.4.0", "March 2026"). Max 255 characters. Must be unique within the project. |
description |
string | no | Version description. Supports markdown. Max 50,000 characters. |
status |
string | no | draft or published. Defaults to draft. |
released_at |
string | no | ISO 8601 datetime for when this version was released. If omitted, set automatically when the version is published. |
Response (201 Created):
{
"data": {
"id": "ver_2c8e4a1b6f3d",
"name": "2.4.0",
"description": "This release focuses on data import and improved search performance.",
"status": "draft",
"released_at": null,
"created_at": "2026-03-16 09:00:00",
"updated_at": "2026-03-16 09:00:00"
}
}
Error responses:
422— Validation error.409— Duplicate version name.
{
"error": {
"code": "duplicate_version_name",
"message": "A version named '2.4.0' already exists.",
"docs": "https://docs.minolith.io/api/changelog#create-version"
}
}
402— Spending cap exceeded.
List Versions
GET /v1/changelog/versions
Returns a paginated list of versions for the authenticated project.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter by status: draft or published |
limit |
integer | Number of results (1-100, default 20) |
cursor |
string | Cursor from a previous response's pagination.next_cursor |
Example requests:
GET /v1/changelog/versions?status=published&limit=10
GET /v1/changelog/versions?status=draft
Response (200 OK):
{
"data": [
{
"id": "ver_2c8e4a1b6f3d",
"name": "2.4.0",
"description": "This release focuses on data import and improved search performance.",
"status": "published",
"released_at": "2026-03-17 14:30:00",
"created_at": "2026-03-16 09:00:00",
"updated_at": "2026-03-17 14:30:00"
},
{
"id": "ver_5a1d9e7b3c4f",
"name": "2.3.0",
"description": "Bug fixes and performance improvements.",
"status": "published",
"released_at": "2026-03-01 10:00:00",
"created_at": "2026-02-28 11:00:00",
"updated_at": "2026-03-01 10:00:00"
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"limit": 20
}
}
Get Version
GET /v1/changelog/versions/:id
Returns a single version with its entries attached.
Response (200 OK):
{
"data": {
"id": "ver_2c8e4a1b6f3d",
"name": "2.4.0",
"description": "This release focuses on data import and improved search performance.",
"status": "published",
"released_at": "2026-03-17 14:30:00",
"created_at": "2026-03-16 09:00:00",
"updated_at": "2026-03-17 14:30:00",
"entries": [
{
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB...",
"category": "feature",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:30:00"
},
{
"id": "ent_9d4b1e7c3a2f",
"title": "Fix timezone handling in scheduled exports",
"body": "Scheduled exports now correctly use the project timezone...",
"category": "fix",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-16 16:45:00",
"updated_at": "2026-03-17 14:30:00"
}
]
}
}
Error responses:
404— Version not found.
{
"error": {
"code": "version_not_found",
"message": "Version 'ver_nonexistent' not found in this project.",
"docs": "https://docs.minolith.io/api/changelog#get-version"
}
}
Update Version
PUT /v1/changelog/versions/:id
Partially updates an existing version. Only include the fields you want to change. Free — no credit cost.
Request body (all fields optional):
{
"name": "2.4.1",
"description": "Patch release with critical fix for CSV import."
}
| Field | Type | Description |
|---|---|---|
name |
string | Max 255 characters, must be unique within the project |
description |
string | Max 50,000 characters, markdown |
status |
string | draft or published |
released_at |
string | ISO 8601 datetime |
Response (200 OK):
Returns the full updated version (without entries array).
Error responses:
404— Version not found.409— Duplicate version name.422— Validation error.
Delete Version
DELETE /v1/changelog/versions/:id
Permanently deletes a version. Only draft versions can be deleted. Published versions must be kept for historical accuracy. When a version is deleted, its entries become ungrouped (version_id is set to null). Free — no credit cost.
Response (204 No Content):
Empty response body.
Error responses:
404— Version not found.403— Published versions cannot be deleted.
{
"error": {
"code": "cannot_delete_published_version",
"message": "Published versions cannot be deleted.",
"docs": "https://docs.minolith.io/api/changelog#delete-version"
}
}
Publish Version
POST /v1/changelog/versions/:id/publish
Publishes the version and all of its draft entries in a single operation. If released_at is not already set, it is set to the current time. Free — no credit cost.
Request body: None.
Response (200 OK):
{
"data": {
"id": "ver_2c8e4a1b6f3d",
"name": "2.4.0",
"description": "This release focuses on data import and improved search performance.",
"status": "published",
"released_at": "2026-03-17 14:30:00",
"created_at": "2026-03-16 09:00:00",
"updated_at": "2026-03-17 14:30:00"
}
}
Error responses:
404— Version not found.
Public Endpoint
Get Public Changelog
GET /v1/changelog/public/:slug
Returns published entries for a project. No authentication required. Rate limited by IP address.
The :slug is the project's public slug, configured in the Minolith dashboard.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
limit |
integer | Number of entries (1-100, default 20) |
Example request:
GET /v1/changelog/public/my-project?limit=50
Response (200 OK):
{
"data": [
{
"id": "ent_7f3a9b2c4d1e",
"title": "Add bulk import for CSV files",
"body": "Users can now import records from CSV files up to 50MB...",
"category": "feature",
"status": "published",
"version_id": "ver_2c8e4a1b6f3d",
"published_at": "2026-03-17 14:30:00",
"created_at": "2026-03-17 12:00:00",
"updated_at": "2026-03-17 14:30:00"
}
],
"pagination": {
"has_more": false,
"next_cursor": null,
"limit": 20
}
}
Error responses:
404— Project slug not found or has no published entries.
Hosted Page and RSS
Every project with published changelog entries gets a hosted changelog page and RSS feed:
| Resource | URL |
|---|---|
| Hosted page | https://changelog.minolith.io/{project-slug} |
| RSS feed | https://changelog.minolith.io/{project-slug}/feed.xml |
The hosted page displays all published entries grouped by version, with ungrouped entries shown separately. The RSS feed includes the most recent published entries for use in feed readers and monitoring tools.
Widget Embed
Embed a changelog widget on your website or application:
<script src="https://api.minolith.io/widget/changelog.js"
data-project="your-slug"
data-position="bottom-right"></script>
| Attribute | Required | Description |
|---|---|---|
data-project |
yes | Your project's public slug |
data-position |
no | Widget position: bottom-right (default), bottom-left, top-right, top-left |
The widget shows a notification badge when new entries are published and opens a panel with the latest changelog entries.
Validation Rules
| Field | Type | Required | Constraints |
|---|---|---|---|
title (entry) |
string | yes | Max 500 characters |
body (entry) |
string | yes | Max 50,000 characters, markdown |
category |
enum | yes | feature, improvement, fix, breaking, deprecation, security, other |
status (entry) |
enum | no | draft, published. Default: draft |
version_id |
string | no | Must reference an existing version in the same project, or null |
name (version) |
string | yes | Max 255 characters. Unique per project. |
description (version) |
string | no | Max 50,000 characters, markdown |
status (version) |
enum | no | draft, published. Default: draft |
released_at |
string | no | ISO 8601 datetime (e.g. 2026-03-17T14:30:00Z) |
Credit Costs
| Action | Credits | Cost |
|---|---|---|
| Entry created | 3 | $0.03 |
| Version created | 0 | Free |
| All other operations (reads, updates, deletes, publish, unpublish) | 0 | Free |
Error Codes
| Code | HTTP | Message |
|---|---|---|
invalid_category |
422 | Category '{value}' is not valid. Accepted values are: feature, improvement, fix, breaking, deprecation, security, other. |
version_not_found |
404 | Version '{id}' not found in this project. |
duplicate_version_name |
409 | A version named '{name}' already exists. |
cannot_delete_published_version |
403 | Published versions cannot be deleted. |
entry_already_published |
409 | Entry is already published. |
entry_already_draft |
409 | Entry is already a draft. |
spending_cap_exceeded |
402 | Spending cap exceeded. |
validation_error |
422 | Field-specific validation message. |
not_found |
404 | Resource not found. |
unauthorized |
401 | Authentication required. |
rate_limit_exceeded |
429 | Rate limit exceeded. |
ID Format
Entry IDs use the prefix ent_ and version IDs use the prefix ver_, each followed by 12 random hex characters:
ent_7f3a9b2c4d1e
ver_2c8e4a1b6f3d
Always use the full ID (including prefix) when referencing resources in API calls.
Rate Limiting
All authenticated API endpoints are rate-limited to 100 requests per minute per API key. The public endpoint is rate-limited by IP address. See Platform API — Rate Limiting for full details.
MCP Tools
The Changelog service is available via MCP for direct integration with AI coding tools.
Connection
claude mcp add --transport http minolith https://mcp.minolith.io \
--header "Authorization: Bearer mlth_your_api_key_here" \
--header "X-Minolith-Agent: your-agent-name"
create_changelog_entry
Create a new changelog entry. Costs 1 credit.
Input Schema:
{
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Short description of the change. Max 500 characters."
},
"body": {
"type": "string",
"description": "Full details of the change. Supports markdown. Max 50,000 characters."
},
"category": {
"type": "string",
"enum": ["feature", "improvement", "fix", "breaking", "deprecation", "security", "other"],
"description": "Type of change."
},
"status": {
"type": "string",
"enum": ["draft", "published"],
"description": "Entry status. Defaults to draft."
},
"version_id": {
"type": "string",
"description": "ID of a version to group this entry under. Omit for ungrouped."
}
},
"required": ["title", "body", "category"]
}
Example:
{
"name": "create_changelog_entry",
"arguments": {
"title": "Add webhook retry logic",
"body": "Failed webhook deliveries are now retried up to 3 times with exponential backoff.",
"category": "improvement",
"version_id": "ver_2c8e4a1b6f3d"
}
}
list_changelog_entries
List changelog entries with optional filters.
Input Schema:
{
"type": "object",
"properties": {
"status": {
"type": "string",
"enum": ["draft", "published"],
"description": "Filter by status."
},
"category": {
"type": "string",
"description": "Filter by category. Comma-separated for multiple: 'feature,fix'."
},
"version_id": {
"type": "string",
"description": "Filter by version ID. Use 'null' for ungrouped entries."
},
"limit": {
"type": "integer",
"description": "Max entries to return (1-100, default 20)."
}
},
"required": []
}
Example:
{
"name": "list_changelog_entries",
"arguments": {
"status": "draft",
"category": "feature,improvement",
"limit": 50
}
}
create_changelog_version
Create a new changelog version. Costs 1 credit.
Input Schema:
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Version name (e.g. '2.4.0'). Max 255 characters. Must be unique per project."
},
"description": {
"type": "string",
"description": "Version description. Supports markdown. Max 50,000 characters."
},
"status": {
"type": "string",
"enum": ["draft", "published"],
"description": "Version status. Defaults to draft."
},
"released_at": {
"type": "string",
"description": "ISO 8601 datetime for when this version was released."
}
},
"required": ["name"]
}
Example:
{
"name": "create_changelog_version",
"arguments": {
"name": "2.5.0",
"description": "Webhook improvements and new API endpoints."
}
}
publish_changelog_entry
Publish a single changelog entry. Sets status to published and published_at to now.
Input Schema:
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Entry ID (ent_xxxxxxxx)."
}
},
"required": ["id"]
}
Example:
{
"name": "publish_changelog_entry",
"arguments": {
"id": "ent_7f3a9b2c4d1e"
}
}
publish_changelog_version
Publish a version and all its draft entries. Sets released_at if not already set.
Input Schema:
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Version ID (ver_xxxxxxxx)."
}
},
"required": ["id"]
}
Example:
{
"name": "publish_changelog_version",
"arguments": {
"id": "ver_2c8e4a1b6f3d"
}
}
Example Workflows
Simple: Single entry, no version
Create a standalone entry and publish it immediately.
1. POST /v1/changelog/entries
{
"title": "Fix login timeout on slow connections",
"body": "Increased the authentication timeout from 5s to 15s to accommodate users on slow connections.",
"category": "fix"
}
→ 201, returns ent_a3b7c1d9e5f2
2. POST /v1/changelog/entries/ent_a3b7c1d9e5f2/publish
→ 200, entry is now published with published_at set
Versioned: Group entries under a release
Create a version, add entries to it, then publish everything at once.
1. POST /v1/changelog/versions
{ "name": "3.0.0", "description": "Major release with breaking changes." }
→ 201, returns ver_8d2f4a6b1c3e
2. POST /v1/changelog/entries
{
"title": "New REST API v2 with cursor pagination",
"body": "All list endpoints now use cursor-based pagination...",
"category": "breaking",
"version_id": "ver_8d2f4a6b1c3e"
}
→ 201, returns ent_1a2b3c4d5e6f
3. POST /v1/changelog/entries
{
"title": "Add rate limiting headers to all responses",
"body": "Every API response now includes X-RateLimit-* headers...",
"category": "improvement",
"version_id": "ver_8d2f4a6b1c3e"
}
→ 201, returns ent_6f5e4d3c2b1a
4. POST /v1/changelog/versions/ver_8d2f4a6b1c3e/publish
→ 200, version + both entries are now published
Retroactive: Assign existing entries to a new version
Create entries first, then group them into a version later.
1. POST /v1/changelog/entries
{ "title": "Improve search indexing speed", "body": "...", "category": "improvement" }
→ 201, returns ent_4c5d6e7f8a9b
2. POST /v1/changelog/entries
{ "title": "Fix duplicate webhook deliveries", "body": "...", "category": "fix" }
→ 201, returns ent_9b8a7f6e5d4c
3. POST /v1/changelog/versions
{ "name": "2.5.1" }
→ 201, returns ver_3e2d1c4b5a6f
4. PUT /v1/changelog/entries/ent_4c5d6e7f8a9b
{ "version_id": "ver_3e2d1c4b5a6f" }
→ 200
5. PUT /v1/changelog/entries/ent_9b8a7f6e5d4c
{ "version_id": "ver_3e2d1c4b5a6f" }
→ 200
6. POST /v1/changelog/versions/ver_3e2d1c4b5a6f/publish
→ 200, version + both entries are now published