The Patchlog API lets you read your projects and entries, and create, update, and publish changelog entries from your own code, CI pipeline, or AI agent. This page is the complete reference.
If you want an AI agent to drive Patchlog instead of writing HTTP calls yourself, use the MCP server, which wraps this same API.
Basics
- Base URL:
https://patchlog.io/api/v1 - Format: JSON in, JSON out. Send
Accept: application/jsonand, on writes,Content-Type: application/json. - Plan: the API is a Pro feature. Free accounts receive
403on every endpoint.
Authentication
Create a token in Settings, then API Tokens and send it as a bearer token on every request:
curl https://patchlog.io/api/v1/projects \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Tokens are shown once at creation and can be revoked at any time from the same page. A token can only see and change projects owned by the account that created it.
Projects
List projects
GET /api/v1/projects
{
"data": [
{
"id": "01jz9k2m3n4p5q6r7s8t9v0w1x",
"name": "My App",
"slug": "my-app",
"description": "The main product",
"is_public": true,
"url": "https://my-app.patchlog.io",
"entries_count": 12,
"created_at": "2026-05-01T09:30:00+00:00"
}
]
}
Project ids are ULIDs. You will need them for every entry endpoint.
Get one project
GET /api/v1/projects/{projectId}
Returns the same shape as one item of the list above, under data.
Entries
Every entry has this shape:
{
"id": 42,
"title": "CSV export",
"content": "You can now export any report as CSV.",
"type": "feature",
"type_label": "New Feature",
"status": "published",
"published_at": "2026-08-10T14:00:00+00:00",
"source": "api",
"source_ref": null,
"created_at": "2026-08-10T13:58:12+00:00",
"updated_at": "2026-08-10T14:00:00+00:00"
}
content is Markdown. type is one of feature, fix, improvement, security. source is manual, github, or api depending on where the entry came from.
List entries
GET /api/v1/projects/{projectId}/entries
Query parameters:
| Parameter | Values | Default |
|---|---|---|
status |
published, draft, all |
published |
type |
feature, fix, improvement, security |
none |
per_page |
1 to 100 | 25 |
page |
page number | 1 |
status=published returns only live entries: published and not scheduled for the future. all includes drafts and scheduled entries. The response is paginated:
{
"data": [],
"meta": { "current_page": 1, "last_page": 3, "per_page": 25, "total": 61 }
}
Get one entry
GET /api/v1/projects/{projectId}/entries/{entryId}
Create an entry
POST /api/v1/projects/{projectId}/entries
| Field | Required | Notes |
|---|---|---|
title |
yes | max 200 characters |
content |
yes | Markdown |
type |
yes | feature, fix, improvement, security |
status |
no | draft (default) or published |
published_at |
no | ISO 8601 datetime; a future value schedules the entry |
Rules worth knowing: a draft never keeps a published_at; a published entry without a date gets the current time; a future date makes the entry invisible until that time, when the scheduler flips it live. Returns 201 with the entry under data.
curl -X POST https://patchlog.io/api/v1/projects/PROJECT_ID/entries \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"title":"CSV export","content":"You can now export any report as CSV.","type":"feature","status":"published"}'
Update an entry
PATCH /api/v1/projects/{projectId}/entries/{entryId}
Send only the fields you want to change; everything else is left alone. Same fields and rules as create. Setting status to draft unpublishes the entry and clears its date. Returns 200 with the updated entry.
Publish an entry
POST /api/v1/projects/{projectId}/entries/{entryId}/publish
No body. Flips a draft or scheduled entry live right now. An entry that is already live keeps its original published_at, so republishing never reshuffles your changelog's order. Returns 200 with the entry.
Errors
Errors come back as JSON with a message, and validation failures add an errors object keyed by field:
| Status | Meaning |
|---|---|
401 |
Missing or invalid token |
403 |
Not your project, or your plan has no API access |
404 |
Project or entry does not exist |
422 |
Validation failed, or the plan's entry limit was reached |
429 |
Rate limit exceeded |
{
"message": "The title field is required.",
"errors": { "title": ["The title field is required."] }
}
Rate limits
Reads are limited to 120 requests per minute, writes to 30 per minute, per client. A 429 response includes a Retry-After header.
Related tools
- MCP server: let Claude Code, Claude Desktop, or Cursor call this API for you.
- GitHub Action: sends your pushes to Patchlog so drafts get generated automatically on your cadence.
Questions or a missing endpoint you need? Email [email protected].