REST API

Create and update changelog entries from CI/CD, scripts, or your own tools.

Featul3 min read

Overview

The Featul REST API lets you publish changelog entries without opening the app, for example when a release ships. It's available on Starter and Professional.

All requests go to https://api.featul.com/v1 and send and return JSON. If you self-host Featul, use your app's address with /api/v1, for example https://featul.yourcompany.com/api/v1.

Authentication

Workspace owners and admins can create a key in Settings → Integrations → API keys. The key is shown once, so store it as a secret right away (for example FEATUL_API_KEY in GitHub Actions).

Send the key in the Authorization header:

curl https://api.featul.com/v1/changelog \
  -H "Authorization: Bearer $FEATUL_API_KEY"

A key belongs to one workspace and acts as the person who created it. Entries it creates are credited to that person. If they leave the workspace or stop being an owner or admin, the key stops working. Create a new one from an account that still has access.

Revoke a key from the same settings page. Anything using it stops working immediately.

Create or update an entry

POST /v1/changelog

curl -X POST https://api.featul.com/v1/changelog \
  -H "Authorization: Bearer $FEATUL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Faster search",
    "content": "## Improvements\n\n- Search results load twice as fast.",
    "tags": ["Improvement"],
    "status": "published",
    "externalId": "v2.4.0"
  }'
FieldTypeDescription
titlestring, requiredUp to 256 characters.
contentstringMarkdown body. Headings, lists, links, code blocks, and HTTPS images are supported.
summarystringShown in lists and emails. Defaults to the start of the body.
tagsstring[]Changelog tag names. Tags must already exist (create them in Settings → Changelog).
statusdraft or publishedDefaults to draft. Publishing emails changelog subscribers.
scheduledAtISO 8601 datePublish a draft automatically at this time. Only drafts can be scheduled.
externalIdstringYour own id for this update, like a release tag or commit SHA.

Safe retries with externalId

When you send an externalId that already exists, Featul updates that entry instead of creating a new one. Re-running a release workflow or retrying a failed request never creates duplicates. Without externalId, every request creates a new entry.

The response is 201 Created for a new entry and 200 OK for an update.

{
  "data": {
    "id": "k3x9...",
    "title": "Faster search",
    "slug": "faster-search-m2f1a",
    "status": "published",
    "summary": "Search results load twice as fast.",
    "tags": ["Improvement"],
    "externalId": "v2.4.0",
    "url": "https://acme.featul.com/changelog/p/faster-search-m2f1a",
    "publishedAt": "2026-10-25T12:00:00.000Z",
    "scheduledAt": null,
    "createdAt": "2026-10-25T12:00:00.000Z",
    "updatedAt": "2026-10-25T12:00:00.000Z"
  }
}

url uses your custom domain when one is set. It's null for drafts.

Update an entry

PATCH /v1/changelog/:id

Send only the fields you want to change. Send "scheduledAt": null to clear a schedule. For example, publish a draft:

curl -X PATCH https://api.featul.com/v1/changelog/k3x9... \
  -H "Authorization: Bearer $FEATUL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "status": "published" }'

Get an entry

GET /v1/changelog/:id

List entries

GET /v1/changelog

Query parameterDescription
statusdraft or published.
externalIdFind the entry created with this externalId.
limit1 to 100, default 20.
offsetSkip this many entries, default 0.

Entries are newest first. The response is { "data": { "entries": [...], "hasMore": true } }.

Errors

Errors return a status code and a JSON body:

{ "error": { "code": "unknown_tags", "message": "Unknown changelog tags: Beta. Available tags: Fix, New" } }
StatusCodeMeaning
400invalid_request, invalid_json, unknown_tagsThe body or query is invalid. The message says which field.
401unauthorizedMissing, revoked, or expired key, or its creator lost access.
403plan_required, limit_reached, insufficient_scopeThe plan doesn't include the API, the changelog entry limit is reached, or the key can't do this.
404not_foundNo entry with that id in this workspace.
429rate_limitedMore than 60 requests a minute for this key (or 300 from one IP address). Wait for Retry-After seconds.

Next steps

Still stuck?

Post it on the board. The team answers there.

Ask on the board