Scripts and CI jobs can do most of what the Docs and Changelog consoles do: create and configure sites, write and publish pages and entries, upload files, manage domains, read analytics and the activity log. A full API reference for these two products is not published yet. The endpoints on this page are stable and work with an API key today; this page lists them by task, with the scope each one needs.
Paths below are relative to https://evohub.io. Requests need an API key, sent as described in API overview . Answers use the same envelope as the rest of the API: {"data": ...} on success and an error object on failure. See Errors .
# Scopes
Each endpoint needs one scope. Give a key only the ones its job needs.
To
Docs
Changelog
Read sites and everything on them: pages or entries, revisions, analytics, feedback, activity
docs:site:read
changelog:site:read
Create and configure sites: settings, domain, logo, access, versions or categories, redirects, GitHub repository, integrations
docs:site:write
changelog:site:write
Delete a site
docs:site:delete
changelog:site:delete
Write: pages and sections, or entries; files; imports; opening change requests or submitting for review
docs:page:write
changelog:entry:write
Put writing live: publish, unpublish, schedule
docs:page:publish
changelog:entry:publish
The activity log of a site, and of the organization, is read with the site read scope.
A key without the scope gets 403 FORBIDDEN, never 401. A key sees organization-wide sites and, for a personal key, your teams' sites; an organization key scoped to a team sees that team's. A site it cannot see answers 404 , the same as one that does not exist. See API keys and scopes .
# Docs
# Sites
Method
Path
Scope
What it does
GET
/api/v1/docs/sites
docs:site:read
List the sites the key can see
GET
/api/v1/docs/sites/overview
docs:site:read
The list's figures for every site at once
POST
/api/v1/docs/sites
docs:site:write
Create a site
GET
/api/v1/docs/templates
docs:site:read
List the site templates
POST
/api/v1/docs/sites/from-template
docs:site:write
Create a site from a template
GET
/api/v1/docs/starter.zip
docs:site:read
Download the starter project
GET
/api/v1/docs/sites/{siteID}
docs:site:read
Read a site and its settings
PATCH
/api/v1/docs/sites/{siteID}
docs:site:write
Change a site's settings; only the fields you send change
DELETE
/api/v1/docs/sites/{siteID}
docs:site:delete
Delete a site with all its pages and files
POST
/api/v1/docs/sites/{siteID}/publish
docs:site:write
Put the site online or take it offline: {"published": true}
POST
/api/v1/docs/sites/{siteID}/preview
docs:site:read
Create a private preview link of the live site
POST
/api/v1/docs/sites/{siteID}/logo
docs:site:write
Upload the logo
DELETE
/api/v1/docs/sites/{siteID}/logo
docs:site:write
Remove the logo
POST
/api/v1/docs/sites/{siteID}/logo/dark
docs:site:write
Upload the dark-mode logo
DELETE
/api/v1/docs/sites/{siteID}/logo/dark
docs:site:write
Remove the dark-mode logo
GET
/api/v1/docs/sites/{siteID}/export
docs:site:read
Download the whole site as a zip
# Versions and languages
Method
Path
Scope
What it does
GET
/api/v1/docs/sites/{siteID}/versions
docs:site:read
List the site's versions
POST
/api/v1/docs/sites/{siteID}/versions
docs:site:write
Create a version
PATCH
/api/v1/docs/versions/{versionID}
docs:site:write
Change a version
DELETE
/api/v1/docs/versions/{versionID}
docs:site:write
Delete a version
GET
/api/v1/docs/sites/{siteID}/translations
docs:site:read
How far each language's translation has come
GET
/api/v1/docs/pages/{pageID}/translations
docs:site:read
List a page's translations
POST
/api/v1/docs/pages/{pageID}/translations
docs:page:write
Start a translation of a page
# Sections and pages
Method
Path
Scope
What it does
GET
/api/v1/docs/sites/{siteID}/tree
docs:site:read
The navigation: sections and pages in order
PUT
/api/v1/docs/sites/{siteID}/order
docs:page:write
Reorder the navigation, and move pages between sections
POST
/api/v1/docs/sites/{siteID}/sections
docs:page:write
Create a section
PATCH
/api/v1/docs/sections/{sectionID}
docs:page:write
Rename a section
DELETE
/api/v1/docs/sections/{sectionID}
docs:page:write
Delete a section
POST
/api/v1/docs/sites/{siteID}/pages
docs:page:write
Create a page; it starts as a draft
GET
/api/v1/docs/pages/{pageID}
docs:site:read
Read a page: its draft and what is live
PATCH
/api/v1/docs/pages/{pageID}
docs:page:write
Edit a page's draft
DELETE
/api/v1/docs/pages/{pageID}
docs:page:write
Delete a page; a published one also needs docs:page:publish
POST
/api/v1/docs/pages/{pageID}/git/resolve
docs:page:write
Settle a conflict between the page and its GitHub file
# Publishing
Method
Path
Scope
What it does
POST
/api/v1/docs/pages/{pageID}/publish
docs:page:publish
Publish the page's draft
POST
/api/v1/docs/pages/{pageID}/unpublish
docs:page:publish
Take the page off the live site
On a site that requires review, publishing goes through change requests and these answer 409 REVIEW_REQUIRED. Open a change request instead (below); a person approves and merges it.
# Revisions
Method
Path
Scope
What it does
GET
/api/v1/docs/pages/{pageID}/revisions
docs:site:read
List a page's revisions, newest first
GET
/api/v1/docs/pages/{pageID}/revisions/{revisionID}
docs:site:read
Read one revision
POST
/api/v1/docs/pages/{pageID}/revisions/{revisionID}/restore
docs:page:write
Put a revision back into the draft
POST
/api/v1/docs/pages/{pageID}/revisions/{revisionID}/rollback
docs:page:write
Make an earlier publish live again; also needs docs:page:publish, except on a site that requires review, where it opens a change request instead
# Change requests
Method
Path
Scope
What it does
GET
/api/v1/docs/sites/{siteID}/changes
docs:site:read
What is waiting to go live
GET
/api/v1/docs/sites/{siteID}/change-requests
docs:site:read
List change requests
POST
/api/v1/docs/sites/{siteID}/change-requests
docs:page:write
Open a change request
GET
/api/v1/docs/change-requests/{crID}
docs:site:read
Read a change request
PATCH
/api/v1/docs/change-requests/{crID}
docs:page:write
Change its title, description, items or reviewers
GET
/api/v1/docs/change-requests/{crID}/diff
docs:site:read
What it changes, against the live site
POST
/api/v1/docs/change-requests/{crID}/close
docs:page:write
Close it without merging
POST
/api/v1/docs/change-requests/{crID}/reopen
docs:page:write
Reopen a closed one
POST
/api/v1/docs/change-requests/{crID}/refresh
docs:page:write
Bring its items up to date with their drafts
GET
/api/v1/docs/change-requests/{crID}/comments
docs:site:read
List its comments
POST
/api/v1/docs/change-requests/{crID}/comments
docs:page:write or docs:page:publish
Comment on it
DELETE
/api/v1/docs/comments/{commentID}
docs:site:read
Delete one of the key's own comments
POST
/api/v1/docs/change-requests/{crID}/preview
docs:page:write
Create a preview link of the change request
DELETE
/api/v1/docs/change-requests/{crID}/preview
docs:page:write
Withdraw its preview link
# Snippets and API references
Method
Path
Scope
What it does
GET
/api/v1/docs/sites/{siteID}/snippets
docs:site:read
List reusable snippets
POST
/api/v1/docs/sites/{siteID}/snippets
docs:page:write
Create a snippet
GET
/api/v1/docs/snippets/{snippetID}
docs:site:read
Read a snippet
PATCH
/api/v1/docs/snippets/{snippetID}
docs:page:write
Edit a snippet's draft
DELETE
/api/v1/docs/snippets/{snippetID}
docs:page:write
Delete a snippet
POST
/api/v1/docs/snippets/{snippetID}/publish
docs:page:publish
Publish a snippet
POST
/api/v1/docs/snippets/{snippetID}/unpublish
docs:page:publish
Unpublish a snippet
GET
/api/v1/docs/sites/{siteID}/api-specs
docs:site:read
List API references
POST
/api/v1/docs/sites/{siteID}/api-specs
docs:page:write
Add an API reference from an OpenAPI document
GET
/api/v1/docs/api-specs/{specID}
docs:site:read
Read an API reference
PATCH
/api/v1/docs/api-specs/{specID}
docs:page:write
Change an API reference's settings
DELETE
/api/v1/docs/api-specs/{specID}
docs:page:write
Delete an API reference
GET
/api/v1/docs/api-specs/{specID}/file
docs:site:read
Download its OpenAPI document
PUT
/api/v1/docs/api-specs/{specID}/file
docs:page:write
Replace its OpenAPI document, for example from CI
POST
/api/v1/docs/api-specs/{specID}/publish
docs:page:publish
Publish the API reference
POST
/api/v1/docs/api-specs/{specID}/unpublish
docs:page:publish
Unpublish the API reference
# Files and redirects
Method
Path
Scope
What it does
GET
/api/v1/docs/sites/{siteID}/assets
docs:site:read
List uploaded files
POST
/api/v1/docs/sites/{siteID}/assets
docs:page:write
Upload a file
DELETE
/api/v1/docs/assets/{assetID}
docs:page:write
Delete a file
GET
/api/v1/docs/sites/{siteID}/redirects
docs:site:read
List redirects
POST
/api/v1/docs/sites/{siteID}/redirects
docs:site:write
Create a redirect
PATCH
/api/v1/docs/redirects/{redirectID}
docs:site:write
Change a redirect
DELETE
/api/v1/docs/redirects/{redirectID}
docs:site:write
Delete a redirect
# Import and GitHub
Method
Path
Scope
What it does
POST
/api/v1/docs/imports
docs:page:write
Upload content from another tool and get a preview
GET
/api/v1/docs/imports/{importID}
docs:site:read
Read an import and its preview
POST
/api/v1/docs/imports/{importID}/commit
docs:page:write
Import it into a site
DELETE
/api/v1/docs/imports/{importID}
docs:page:write
Discard an import
GET
/api/v1/docs/git/config
docs:site:read
Whether GitHub sync is available
GET
/api/v1/docs/sites/{siteID}/git
docs:site:read
The site's GitHub connection
GET
/api/v1/docs/sites/{siteID}/git/repos
docs:site:write
Repositories the connection can use
GET
/api/v1/docs/sites/{siteID}/git/branches
docs:site:write
Branches of a repository
PUT
/api/v1/docs/sites/{siteID}/git
docs:site:write
Choose the repository, branch, folder and format
DELETE
/api/v1/docs/sites/{siteID}/git
docs:site:write
Disconnect the site from GitHub
POST
/api/v1/docs/sites/{siteID}/git/sync
docs:page:write
Sync from the repository now
Connecting a site to GitHub in the first place is done by a person in the console. See GitHub sync and Import and export .
# Domain and access
Method
Path
Scope
What it does
GET
/api/v1/docs/sites/{siteID}/domain
docs:site:read
The custom domain and its verification state
PUT
/api/v1/docs/sites/{siteID}/domain
docs:site:write
Set the custom domain
DELETE
/api/v1/docs/sites/{siteID}/domain
docs:site:write
Remove the custom domain
GET
/api/v1/docs/sites/{siteID}/access
docs:site:read
Who may read the published site
PUT
/api/v1/docs/sites/{siteID}/access
docs:site:write
Change who may read it
PUT
/api/v1/docs/sites/{siteID}/access/password
docs:site:write
Set the site's password
POST
/api/v1/docs/sites/{siteID}/access/jwt/verify
docs:site:write
Check a reader token against the site's settings
POST
/api/v1/docs/sites/{siteID}/access/sign-out
docs:site:write
Sign every reader out
GET
/api/v1/docs/sites/{siteID}/access/read-tokens
docs:site:write
List read tokens
DELETE
/api/v1/docs/sites/{siteID}/access/read-tokens/{tokenID}
docs:site:write
Revoke a read token
See Custom domain and Private docs .
# Analytics, feedback and link health
Method
Path
Scope
What it does
GET
/api/v1/docs/analytics
docs:site:read
Analytics for every site the key can see
GET
/api/v1/docs/sites/{siteID}/analytics
docs:site:read
A site's page views and readers
GET
/api/v1/docs/sites/{siteID}/analytics/search
docs:site:read
What readers searched for
GET
/api/v1/docs/sites/{siteID}/analytics/ai
docs:site:read
Visits from AI assistants and crawlers
GET
/api/v1/docs/sites/{siteID}/analytics/gaps
docs:site:read
Searches that found nothing
GET
/api/v1/docs/sites/{siteID}/analytics/export.csv
docs:site:read
Download analytics as CSV
GET
/api/v1/docs/sites/{siteID}/feedback
docs:site:read
List readers' feedback
PATCH
/api/v1/docs/feedback/{feedbackID}
docs:page:write
Resolve or reopen feedback
DELETE
/api/v1/docs/feedback/{feedbackID}
docs:page:write
Delete feedback
GET
/api/v1/docs/sites/{siteID}/health
docs:site:read
The live site's link report
POST
/api/v1/docs/sites/{siteID}/health/check
docs:page:write
Check the links again now
# Activity log
Method
Path
Scope
What it does
GET
/api/v1/docs/activity
docs:site:read
What happened across every site the key can see
GET
/api/v1/docs/sites/{siteID}/activity
docs:site:read
What happened on one site
# Changelog
# Sites
Method
Path
Scope
What it does
GET
/api/v1/changelog/sites
changelog:site:read
List the changelogs the key can see
GET
/api/v1/changelog/sites/overview
changelog:site:read
The list's figures for every changelog at once
POST
/api/v1/changelog/sites
changelog:site:write
Create a changelog
GET
/api/v1/changelog/sites/{siteID}
changelog:site:read
Read a changelog and its settings
PATCH
/api/v1/changelog/sites/{siteID}
changelog:site:write
Change its settings; only the fields you send change
DELETE
/api/v1/changelog/sites/{siteID}
changelog:site:delete
Delete a changelog with every entry on it
POST
/api/v1/changelog/sites/{siteID}/publish
changelog:site:write
Put the changelog online or take it offline: {"published": true}
POST
/api/v1/changelog/sites/{siteID}/preview
changelog:site:read
Create a private preview link of the live changelog
POST
/api/v1/changelog/sites/{siteID}/logo
changelog:site:write
Upload the logo
DELETE
/api/v1/changelog/sites/{siteID}/logo
changelog:site:write
Remove the logo
POST
/api/v1/changelog/sites/{siteID}/logo/dark
changelog:site:write
Upload the dark-mode logo
DELETE
/api/v1/changelog/sites/{siteID}/logo/dark
changelog:site:write
Remove the dark-mode logo
# Categories
Method
Path
Scope
What it does
GET
/api/v1/changelog/sites/{siteID}/categories
changelog:site:read
List categories
POST
/api/v1/changelog/sites/{siteID}/categories
changelog:site:write
Create a category
PUT
/api/v1/changelog/sites/{siteID}/categories/order
changelog:site:write
Reorder categories
PATCH
/api/v1/changelog/categories/{categoryID}
changelog:site:write
Change a category
DELETE
/api/v1/changelog/categories/{categoryID}
changelog:site:write
Delete a category
# Entries
Method
Path
Scope
What it does
GET
/api/v1/changelog/sites/{siteID}/entries
changelog:site:read
List entries; filter with status, category, tag and q
POST
/api/v1/changelog/sites/{siteID}/entries
changelog:entry:write
Create an entry; it starts as a draft
GET
/api/v1/changelog/entries/{entryID}
changelog:site:read
Read an entry with its review state
PATCH
/api/v1/changelog/entries/{entryID}
changelog:entry:write
Edit an entry's draft
DELETE
/api/v1/changelog/entries/{entryID}
changelog:entry:write
Delete an entry; a published one also needs changelog:entry:publish
# Publishing
Method
Path
Scope
What it does
POST
/api/v1/changelog/entries/{entryID}/submit
changelog:entry:write
Submit the draft for review
POST
/api/v1/changelog/entries/{entryID}/publish
changelog:entry:publish
Publish the draft now
POST
/api/v1/changelog/entries/{entryID}/schedule
changelog:entry:publish
Publish at a later time: {"publish_at": "…"}
POST
/api/v1/changelog/entries/{entryID}/unschedule
changelog:entry:publish
Cancel a scheduled publish
POST
/api/v1/changelog/entries/{entryID}/unpublish
changelog:entry:publish
Take the entry off the changelog
POST
/api/v1/changelog/entries/{entryID}/git/resolve
changelog:entry:publish
Settle a conflict between the entry and its GitHub file
On a changelog that requires review, publishing and scheduling need the approvals first and otherwise answer 409 REVIEW_REQUIRED. A key can submit an entry; a person approves it. See Writing entries .
# Revisions and images
Method
Path
Scope
What it does
GET
/api/v1/changelog/entries/{entryID}/revisions
changelog:site:read
List an entry's revisions
GET
/api/v1/changelog/entries/{entryID}/revisions/{revisionID}
changelog:site:read
Read one revision
POST
/api/v1/changelog/entries/{entryID}/revisions/{revisionID}/restore
changelog:entry:write
Put a revision back into the draft
GET
/api/v1/changelog/sites/{siteID}/assets
changelog:site:read
List uploaded images
POST
/api/v1/changelog/sites/{siteID}/assets
changelog:entry:write
Upload an image
DELETE
/api/v1/changelog/assets/{assetID}
changelog:entry:write
Delete an image
# Subscribers
Method
Path
Scope
What it does
GET
/api/v1/changelog/sites/{siteID}/email
changelog:site:read
How email goes out to subscribers
GET
/api/v1/changelog/sites/{siteID}/subscribers
changelog:site:read
List subscribers
GET
/api/v1/changelog/sites/{siteID}/subscribers/export.csv
changelog:site:write
Download subscribers as CSV
DELETE
/api/v1/changelog/subscribers/{subscriberID}
changelog:site:write
Remove a subscriber
# Slack and webhooks
Method
Path
Scope
What it does
GET
/api/v1/changelog/chat-channels
changelog:site:write
Chat app channels an integration can post to
GET
/api/v1/changelog/sites/{siteID}/webhooks
changelog:site:write
List integrations
POST
/api/v1/changelog/sites/{siteID}/webhooks
changelog:site:write
Create an integration
PATCH
/api/v1/changelog/webhooks/{webhookID}
changelog:site:write
Change an integration
DELETE
/api/v1/changelog/webhooks/{webhookID}
changelog:site:write
Delete an integration
POST
/api/v1/changelog/webhooks/{webhookID}/test
changelog:site:write
Send a test delivery
POST
/api/v1/changelog/webhooks/{webhookID}/rotate-secret
changelog:site:write
Replace the signing secret
GET
/api/v1/changelog/webhooks/{webhookID}/deliveries
changelog:site:write
Recent deliveries and their results
See Reaching readers .
# GitHub
Method
Path
Scope
What it does
GET
/api/v1/changelog/git/config
changelog:site:read
Whether GitHub sync is available
GET
/api/v1/changelog/sites/{siteID}/git
changelog:site:read
The changelog's GitHub connection
GET
/api/v1/changelog/sites/{siteID}/git/repos
changelog:site:write
Repositories the connection can use
GET
/api/v1/changelog/sites/{siteID}/git/branches
changelog:site:write
Branches of a repository
PUT
/api/v1/changelog/sites/{siteID}/git
changelog:site:write
Choose the repository and branch
DELETE
/api/v1/changelog/sites/{siteID}/git
changelog:site:write
Disconnect from GitHub
POST
/api/v1/changelog/sites/{siteID}/git/sync
changelog:entry:write
Sync from the repository now
POST
/api/v1/changelog/sites/{siteID}/imports/github
changelog:entry:write
Import GitHub releases as entries
Connecting a changelog to GitHub in the first place is done by a person in the console. See GitHub .
# Domain and access
Method
Path
Scope
What it does
GET
/api/v1/changelog/sites/{siteID}/domain
changelog:site:read
The custom domain and its verification state
PUT
/api/v1/changelog/sites/{siteID}/domain
changelog:site:write
Set the custom domain
DELETE
/api/v1/changelog/sites/{siteID}/domain
changelog:site:write
Remove the custom domain
GET
/api/v1/changelog/sites/{siteID}/access
changelog:site:read
Who may read the changelog
PUT
/api/v1/changelog/sites/{siteID}/access
changelog:site:write
Change who may read it
PUT
/api/v1/changelog/sites/{siteID}/access/password
changelog:site:write
Set the changelog's password
POST
/api/v1/changelog/sites/{siteID}/access/sign-out
changelog:site:write
Sign every reader out
# Analytics and feedback
Method
Path
Scope
What it does
GET
/api/v1/changelog/analytics
changelog:site:read
Analytics for every changelog the key can see
GET
/api/v1/changelog/sites/{siteID}/analytics
changelog:site:read
A changelog's views and readers
GET
/api/v1/changelog/sites/{siteID}/analytics/export.csv
changelog:site:read
Download analytics as CSV
GET
/api/v1/changelog/sites/{siteID}/feedback
changelog:site:read
List readers' feedback
PATCH
/api/v1/changelog/feedback/{feedbackID}
changelog:site:write
Resolve or reopen feedback
DELETE
/api/v1/changelog/feedback/{feedbackID}
changelog:site:write
Delete feedback
# Activity log
Method
Path
Scope
What it does
GET
/api/v1/changelog/activity
changelog:site:read
What happened across every changelog the key can see
GET
/api/v1/changelog/sites/{siteID}/activity
changelog:site:read
What happened on one changelog
# Create and publish a changelog entry
A release pipeline can write the entry and publish it in two calls. The key needs changelog:entry:write and changelog:entry:publish.
curl https://evohub.io/api/v1/changelog/sites/$SITE_ID /entries \
-H "Authorization: Bearer $EVOHUB_API_KEY " \
-H "Content-Type: application/json" \
-d '{
"title": "Faster exports",
"summary": "CSV exports now finish in seconds.",
"body_md": "Exports of large projects used to take minutes. They now stream as they are built.",
"version": "2.4.0",
"category_ids": ["' "$CATEGORY_ID " '"],
"tags": ["exports"]
}'
curl -X POST https://evohub.io/api/v1/changelog/entries/$ENTRY_ID /publish \
-H "Authorization: Bearer $EVOHUB_API_KEY " \
-H "Content-Type: application/json" \
-d '{"notify": true}'
title is required; a blank slug is made from the title. The answer to the first call is the entry, with its id. notify is optional; leave it out to keep the entry's setting. To publish later instead, call /schedule with {"publish_at": "2026-12-01T09:00:00Z"}. Entry fields also include cover_image_url, pinned, author_name and date.
# Update and publish a docs page
curl -X PATCH https://evohub.io/api/v1/docs/pages/$PAGE_ID \
-H "Authorization: Bearer $EVOHUB_API_KEY " \
-H "Content-Type: application/json" \
-H 'If-Match: "7"' \
-d '{"title": "Install the CLI", "body_md": "Run `brew install acme` and sign in."}'
curl -X POST https://evohub.io/api/v1/docs/pages/$PAGE_ID /publish \
-H "Authorization: Bearer $EVOHUB_API_KEY "
Every save answers with an ETag holding the page's version. Send it back as If-Match (or as version in the body) and a save made over someone else's newer edit is refused with 409 EDIT_CONFLICT, carrying the page as it now stands; leave both out to overwrite. A page's section is changed with PUT /api/v1/docs/sites/{siteID}/order, not on the page. To create a page, POST /api/v1/docs/sites/{siteID}/pages with title, and optionally slug, body_md and section_id; ?version= picks the docs version, and the default version is used without it.
On a site that requires review, step 2 answers 409 REVIEW_REQUIRED: open a change request for the page with POST /api/v1/docs/sites/{siteID}/change-requests and a title, and a person approves and merges it.
# What is not part of the API
Reserved for a person. Approving, requesting changes on, merging and reverting docs change requests and approving changelog entries; connecting a docs site or a changelog to GitHub; and issuing private docs credentials (a new reader-token signing secret, a test token, a read token) are done by a person in the console. A key gets 403 PERSON_REQUIRED. See What a key can never do .
Public-site routes. The addresses under /api/v1/docs/public/ and /api/v1/changelog/public/ serve your published sites to their visitors. They are not part of the API, may change without notice, and do not take an API key.
Console-only helpers such as the console home, notifications and who-is-editing indicators are left out here.