The Notiondesk API reads everything your help center publishes: every article and collection in any language, with its content as markdown, its publication status and its sync state, plus your published changelog entries. Use it to back up your help center, feed your content to another tool, or check which articles failed to sync.
The API reads content but never writes it. Your articles and collections stay in Notion: to change one, edit it in Notion and trigger a sync.
In the Notiondesk API, a collection is called a category.
| Method | Path | Scope | Does |
|---|---|---|---|
GET | /sites/{site_id}/articles | read | Lists articles in one language |
GET | /sites/{site_id}/articles/{article_id} | read | Reads one article with its markdown content |
GET | /sites/{site_id}/categories | read | Lists collections in one language, with their hierarchy |
GET | /sites/{site_id}/categories/{category_id} | read | Reads one collection with its markdown content |
GET | /sites/{site_id}/changelog | read | Lists published changelog entries, newest first |
Choose the language
Every route on this page takes an optional locale query parameter, such as ?locale=fr. Without it, the response uses the help center's default language. On the list routes, locale must be one of the languages the help center serves: the supported_locales of the help center. Read Support multiple languages in your Help Center to add languages.
List articles
curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/articles?page_size=100&locale=en" \
-H "Authorization: Bearer $NOTIONDESK_API_KEY" \
-H "nd-version: 2026-10-16"The list includes every article in every status, drafts and archived articles too, in the order they were created. Page through it with page_size and cursor, as described in Paginate and version Notiondesk API requests.
{
"object": "list",
"data": [
{
"id": "1761580412",
"title": "Connect your Notion workspace",
"slug": "connect-your-notion-workspace",
"status": "published",
"categories": [
{"id": "910000002", "name": "Connecting Notion", "slug": "connecting-notion", "locale": "en", "status": "published"}
],
"tags": [{"name": "Setup", "slug": "setup"}],
"locales_count": 2,
"updated_at": "2026-10-18T14:39:03+00:00",
"published_at": "2026-10-05T04:39:04+00:00",
"locale": "en",
"reading_time": 3,
"views_count": 42,
"reactions_percent": {"smiley": 50, "neutral_face": 25, "disappointed": 25},
"source_notion_page_id": "3d5001d0-2470-8122-a1b2-c3d4e5f60789",
"notion_article_page_url": "https://www.notion.so/3d5001d024708122a1b2c3d4e5f60789",
"sync_in_progress": false,
"sync_timeout": false,
"sync_failed": false,
"sync_error_code": null,
"auto_translated": false
}
],
"has_more": true,
"next_cursor": "OPAQUE_CURSOR"
}| Field | Meaning |
|---|---|
id | The article identifier, used as article_id to read the article |
title, slug | The article title and its path segment on the help center |
status | draft, published, review or archived. See How to control article visibility |
categories | The collections the article belongs to, each with id, name, slug, locale and status |
tags | The article's tags, each with name and slug |
locales_count | How many languages the article exists in |
updated_at, published_at | When the article last changed and when it was published |
locale | The language of this item |
reading_time | Estimated reading time, in minutes |
views_count | How many times readers opened the article |
reactions_percent | Each reader reaction with its share of all reactions, in percent. The reaction names depend on your feedback style |
source_notion_page_id, notion_article_page_url | The Notion page the article syncs from, and the URL of this language's Notion page (null for an automatic translation) |
sync_in_progress, sync_timeout, sync_failed, sync_error_code | Whether a sync of the article is running, and whether the last one timed out or failed, and why |
auto_translated | Whether this language was produced by automatic translation |
sync_failed: true to find every article whose last sync failed, then fix it in Notion and sync it again.Read an article as markdown
curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/articles/1761580412?locale=en" \
-H "Authorization: Bearer $NOTIONDESK_API_KEY" \
-H "nd-version: 2026-10-16"{
"id": "1761580412",
"type": "article",
"title": "Connect your Notion workspace",
"slug": "connect-your-notion-workspace",
"text": "# Connect your Notion workspace\n\nOpen **Settings**, then **Notion**...",
"url": "https://help.example.com/en/articles/connect-your-notion-workspace",
"locale": "en",
"last_updated": "2026-10-18T14:39:03+00:00",
"category": {"id": "910000002", "title": "Connecting Notion", "slug": "connecting-notion"},
"tags": ["setup"],
"truncated": false,
"author": {"name": "Ada Lovelace"},
"status": "published",
"content_available": true,
"sync_in_progress": false,
"sync_timeout": false,
"sync_failed": false,
"sync_error_code": null
}| Field | Meaning |
|---|---|
type | Always article |
text | The article content as markdown. Empty when no content is stored yet |
truncated | true when text was cut at 200,000 bytes. The cut always falls on a whole character |
content_available | Whether Notiondesk holds content for this language yet |
url | The article's public address |
category | The article's main collection: id, title and slug |
tags | The slugs of the article's tags |
author | The article author: name |
Every status is readable, so you can read a draft before you publish it. An article with no translation in the requested locale answers 404 not_found.
List collections
curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/categories?page_size=100" \
-H "Authorization: Bearer $NOTIONDESK_API_KEY" \
-H "nd-version: 2026-10-16"Each item is a collection in the requested language, in the order collections were created:
{
"id": "910000001",
"name": "Getting Started",
"slug": "getting-started",
"updated_at": "2026-10-18T14:39:12+00:00",
"locale": "en",
"is_parent": true,
"source_notion_page_id": "5d5001d0-2470-8122-a1b2-c3d4e5f60789",
"notion_category_page_url": "https://www.notion.so/5d5001d024708122a1b2c3d4e5f60789",
"sync_in_progress": false,
"sync_timeout": false,
"sync_failed": false,
"sync_error_code": null,
"parent_ids": [],
"children_ids": ["910000002"],
"locales_count": 2,
"status": "published",
"auto_translated": false
}Rebuild your collection tree with three fields:
| Field | Meaning |
|---|---|
is_parent | true for a collection at the top of the hierarchy |
parent_ids | The collections directly above this one |
children_ids | The collections directly below this one |
The list carries no article counts. To count a collection's articles, list the articles and group them by categories. Learn how collections organize your help center in Use collections to organize your articles.
Read a collection
curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/categories/910000001?locale=en" \
-H "Authorization: Bearer $NOTIONDESK_API_KEY" \
-H "nd-version: 2026-10-16"The response has the same shape as an article: type is category, title, slug, url, status, the sync fields, and text with the collection's own content as markdown, empty when it has none.
List changelog entries
curl "https://api.notiondesk.so/sites/c74781f6-1aea-4e17-ab23-bbb8b4d174b6/changelog?page_size=50&locale=en" \
-H "Authorization: Bearer $NOTIONDESK_API_KEY" \
-H "nd-version: 2026-10-16"The changelog lists the published articles filed under your changelog collections, newest first. Set it up with Setting up changelogs on your help center.
{
"object": "list",
"data": [
{
"id": "article:1761497350",
"title": "Multilingual sync is now available",
"slug": "multilingual-sync-is-now-available",
"text": "Help centers on the Enterprise plan can now sync every configured locale in a single run instead of one language at a time.",
"published_at": "2026-10-13T09:12:44+00:00",
"last_updated": "2026-10-18T14:39:03+00:00",
"tags": [],
"url": "https://help.example.com/en/changelogs",
"locale": "en"
}
],
"has_more": true,
"next_cursor": "OPAQUE_CURSOR"
}| Field | Meaning |
|---|---|
id | article: followed by the entry's article id. Remove the prefix to read the full entry with the article route |
text | The entry's plain text, usually an excerpt of about 30 words |
published_at, last_updated | When the entry was published and when it last changed |
tags | The slugs of the entry's tags |
url | Your changelog page in this language |
Good to know:
- An entry appears only when its changelog collection is published in the requested language.
- On a help center that uses guest accounts, the list shows only the entries every reader can see.
- The list reaches at most the 1,000 newest entries. Past that,
has_moreisfalseeven when older entries exist.
- Rarely, during a temporary service issue, a list read can skip or repeat an entry. Read it again later for a complete list.
Errors
| Status | code | When |
|---|---|---|
| 400 | validation_error | page_size is outside 1 to 100, the cursor is invalid, locale is not a language the help center serves (lists) or is not 2 to 10 characters (single reads), or the query has an unknown parameter |
| 403 | insufficient_scope | The key lacks the read scope |
| 403 | permission_denied | Changelog only: the changelog is turned off or not included in your plan, or the help center's analytics are turned off |
| 404 | not_found | The help center, article or collection does not exist in your workspace, it has no translation in locale, or the changelog is on but has no changelog collection |
Every route can also answer invalid_version, authentication_error, rate_limited and internal_error. See Handle Notiondesk API errors, rate limits, and retries.
Common questions
Can I create or edit articles with the Notiondesk API?
No. Notion is the source of truth for your content. Edit the article in Notion, then trigger a sync with the API or wait for scheduled sync.
Does the article list include drafts?
Yes. The list and the read route include every status: draft, published, review and archived. Filter the results in your code on status to keep only published articles.
How do I export every article as markdown?
List the articles, then read each one by its id. The examples article has a complete backup script.
What does truncated: true mean?
truncated: true mean?The article's markdown is longer than 200,000 bytes, so text holds the first 200,000 bytes, cut on a whole character.
Why is notion_article_page_url empty for some languages?
notion_article_page_url empty for some languages?That language was produced by automatic translation, so it has no Notion page of its own.