Patchlog
Patchlog
Back to blog
api

Patchlog API Documentation

The complete reference for the Patchlog REST API: authentication, projects, changelog entries, creating and publishing entries, errors, and rate limits.

· 4 min read

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

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

Questions or a missing endpoint you need? Email [email protected].

Keep your customers in the loop

Patchlog gives your app an in-app changelog widget and a hosted updates page in minutes. One script tag, no SDK.

Start for free →

Free plan available. No credit card required.