Articles
Help articles, each belonging to one category.
Service: help.articles
Help articles, each belonging to one category. The article body is Markdown source (body, pg.Text). is_public controls visibility: an article is a draft until explicitly published. priority drives the curated position on the help index and the sidebar — list sort is (-priority, -updated_at): larger priority sorts higher; priority=0 (the default) means “no manual priority” and the article sorts by -updated_at relative to other priority=0 rows.
Fields
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
— | Primary key. Read-only, auto-generated |
slug |
string |
✅ | URL slug; unique across all articles |
category_id |
string |
✅ | Parent category id. Deleting the category cascades to its articles |
title |
string |
✅ | Article title (default-locale / English) |
description |
string |
One-sentence summary shown on the category card / article header. Default "" |
|
body |
string |
✅ | Article body as Markdown source |
is_public |
boolean |
Whether the article is publicly visible (draft until explicitly published). Default false |
|
priority |
integer |
Curated priority on the help index and the sidebar (larger = higher). 0 (default) = no manual priority, sorts by -updated_at. List sort: -priority, -updated_at |
|
created_at |
string |
— | ISO 8601 creation timestamp. Read-only |
updated_at |
string |
— | ISO 8601 last update timestamp. Read-only |
article_translation |
ArticleTranslation[] | Per-locale overlays. Inline — edited on the parent form, not a top-level service | |
article_author |
ArticleAuthor[] | Authors attributed for editorial history. Admin-only — not exposed publicly |
Filterable: category_id · is_public
ArticleTranslation
Inline overlay edited on the Article form, not published as a top-level service. Translatable text fields are nullable so a partial translation keeps the base value where the overlay is NULL (NULL = inherit base); is_public is non-nullable (each locale is published independently). UniqueConstraint(["source_id", "language_id"]) — one translation per (article, language). language_id FK → common_language with on_delete=PROTECT: deleting a language still referenced by translations is blocked.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
— | Primary key. Read-only. Omit when creating |
source_id |
string |
— | Parent article id. Read-only, auto-set from the parent |
language_id |
string |
✅ | Language of this translation (FK → common_language) |
title |
string? |
Translated article title. null = inherit base |
|
description |
string? |
Translated article description. null = inherit base |
|
body |
string? |
Translated article body as Markdown. null = inherit base |
|
is_public |
boolean |
Whether this translation is publicly visible (draft until explicitly published). Default false |
|
created_at |
string |
— | ISO 8601 creation timestamp. Read-only |
updated_at |
string |
— | ISO 8601 last update timestamp. Read-only |
ArticleAuthor
Junction table: article ↔ user (author), edited inline on the Article form as an “Authors” block. Kept for editorial history and admin attribution — not exposed publicly (the help-web frontend does not list authors on articles). Mirrors blog.PostAuthor in shape and on-delete semantics.
| Field | Type | Required | Description |
|---|---|---|---|
id |
string |
— | Primary key. Read-only. Omit when creating |
article_id |
string |
— | Parent article id. Read-only, auto-set from the parent |
user_id |
string |
✅ | Author (FK → accounts_user) |
UniqueConstraint(["article_id", "user_id"]) — an author can be attributed to an article at most once. Both sides cascade: deleting the article or the user removes the junction row.
find
List articles with filtering, sorting, and pagination. Default list sort is (-priority, -updated_at); pass sort to override.
HTTP
Request
GET /v1/help/articles?filter={"category_id":{"$eq":"1920438291700"},"is_public":{"$eq":true}}&fields=id,slug,category_id,title,description,is_public,priority,updated_at&sort=[{"field":"priority","dir":"desc"},{"field":"updated_at","dir":"desc"}]&limit=100
Authorization: Bearer <token>
Response
{
"items": [
{
"id": "1920438292100",
"slug": "install-enbox",
"category_id": "1920438291700",
"title": "Install Enbox on your devices",
"description": "Desktop, mobile, and browser extensions.",
"is_public": true,
"priority": 10,
"updated_at": "2026-05-13T18:30:00Z"
},
{
"id": "1920438292110",
"slug": "first-note",
"category_id": "1920438291700",
"title": "Create your first note",
"description": "Capture, edit, and find notes.",
"is_public": true,
"priority": 0,
"updated_at": "2026-05-10T12:00:00Z"
}
],
"total": 2
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.find",
"params": {
"filter": {
"category_id": { "$eq": "1920438291700" },
"is_public": { "$eq": true }
},
"fields": [
"id", "slug", "category_id", "title", "description",
"is_public", "priority", "updated_at"
],
"sort": [
{ "field": "priority", "dir": "desc" },
{ "field": "updated_at", "dir": "desc" }
],
"limit": 100
},
"id": 10
}
Response
{
"jsonrpc": "2.0",
"result": {
"items": [
{
"id": "1920438292100",
"slug": "install-enbox",
"category_id": "1920438291700",
"title": "Install Enbox on your devices",
"description": "Desktop, mobile, and browser extensions.",
"is_public": true,
"priority": 10,
"updated_at": "2026-05-13T18:30:00Z"
},
{
"id": "1920438292110",
"slug": "first-note",
"category_id": "1920438291700",
"title": "Create your first note",
"description": "Capture, edit, and find notes.",
"is_public": true,
"priority": 0,
"updated_at": "2026-05-10T12:00:00Z"
}
],
"total": 2
},
"id": 10
}
findOneById
Fetch a single article with full detail, including the Markdown body and translations.
HTTP
Request
GET /v1/help/articles/1920438292100?fields=id,slug,category_id,title,description,body,is_public,priority,created_at,updated_at,article_translation.id,article_translation.language_id,article_translation.title,article_translation.description,article_translation.body,article_translation.is_public
Authorization: Bearer <token>
Response
{
"id": "1920438292100",
"slug": "install-enbox",
"category_id": "1920438291700",
"title": "Install Enbox on your devices",
"description": "Desktop, mobile, and browser extensions.",
"body": "## Desktop\n\nDownload the installer for [macOS](...) or [Windows](...).\n\n## Mobile\n\nGet Enbox from the App Store or Google Play.",
"is_public": true,
"priority": 10,
"created_at": "2026-05-01T10:30:00Z",
"updated_at": "2026-05-13T18:30:00Z",
"article_translation": [
{
"id": "1920438292120",
"language_id": "1920438290002",
"title": "Installer Enbox sur vos appareils",
"description": null,
"body": "## Bureau\n\nTéléchargez l'installateur pour [macOS](...) ou [Windows](...).",
"is_public": false
}
]
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.findOneById",
"params": {
"id": "1920438292100",
"fields": [
"id", "slug", "category_id", "title", "description", "body",
"is_public", "priority", "created_at", "updated_at",
"article_translation.id", "article_translation.language_id",
"article_translation.title", "article_translation.description",
"article_translation.body", "article_translation.is_public"
]
},
"id": 11
}
Response
{
"jsonrpc": "2.0",
"result": {
"id": "1920438292100",
"slug": "install-enbox",
"category_id": "1920438291700",
"title": "Install Enbox on your devices",
"description": "Desktop, mobile, and browser extensions.",
"body": "## Desktop\n\nDownload the installer for [macOS](...) or [Windows](...).\n\n## Mobile\n\nGet Enbox from the App Store or Google Play.",
"is_public": true,
"priority": 10,
"created_at": "2026-05-01T10:30:00Z",
"updated_at": "2026-05-13T18:30:00Z",
"article_translation": [
{
"id": "1920438292120",
"language_id": "1920438290002",
"title": "Installer Enbox sur vos appareils",
"description": null,
"body": "## Bureau\n\nTéléchargez l'installateur pour [macOS](...) ou [Windows](...).",
"is_public": false
}
]
},
"id": 11
}
create
Create a new article. The server assigns id, created_at, and updated_at. New articles default to is_public: false (draft) and priority: 0.
HTTP
Request
POST /v1/help/articles
Authorization: Bearer <token>
Content-Type: application/json
{
"document": {
"slug": "reset-password",
"category_id": "1920438291730",
"title": "Reset your password",
"description": "Recover access when you forget your password.",
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email and follow the link.",
"is_public": false,
"priority": 5,
"article_translation": [
{
"language_id": "1920438290002",
"title": "Réinitialiser votre mot de passe",
"is_public": false
}
]
}
}
Response
{
"id": "1920438292130",
"slug": "reset-password",
"title": "Reset your password",
"is_public": false,
"priority": 5,
"created_at": "2026-05-13T18:30:00Z"
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.create",
"params": {
"document": {
"slug": "reset-password",
"category_id": "1920438291730",
"title": "Reset your password",
"description": "Recover access when you forget your password.",
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email and follow the link.",
"is_public": false,
"priority": 5,
"article_translation": [
{
"language_id": "1920438290002",
"title": "Réinitialiser votre mot de passe",
"is_public": false
}
]
}
},
"id": 12
}
Response
{
"jsonrpc": "2.0",
"result": {
"id": "1920438292130",
"slug": "reset-password",
"title": "Reset your password",
"is_public": false,
"priority": 5,
"created_at": "2026-05-13T18:30:00Z"
},
"id": 12
}
updateOneById
Partial update — only specified fields change; omitted fields are untouched. Nested collections (article_translation, article_author) are updated automatically: items with id are updated, items without id are created, items missing from the array are deleted.
HTTP
Request
PATCH /v1/help/articles/1920438292130
Authorization: Bearer <token>
Content-Type: application/json
{
"document": {
"is_public": true,
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email.\n4. Check your inbox for the reset link.",
"priority": 15
}
}
Response
{
"id": "1920438292130",
"is_public": true,
"priority": 15,
"updated_at": "2026-05-13T18:45:00Z"
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.updateOneById",
"params": {
"id": "1920438292130",
"document": {
"is_public": true,
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email.\n4. Check your inbox for the reset link.",
"priority": 15
}
},
"id": 13
}
Response
{
"jsonrpc": "2.0",
"result": {
"id": "1920438292130",
"is_public": true,
"priority": 15,
"updated_at": "2026-05-13T18:45:00Z"
},
"id": 13
}
replaceOneById
Full replacement — all writable fields must be provided. Unlike updateOneById, omitted fields are reset to defaults. Nested collections (article_translation, article_author) are not accepted in this method — use updateOneById to modify them.
HTTP
Request
PUT /v1/help/articles/1920438292130
Authorization: Bearer <token>
Content-Type: application/json
{
"document": {
"slug": "reset-password",
"category_id": "1920438291730",
"title": "Reset your password",
"description": "Recover access when you forget your password.",
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email and follow the link.",
"is_public": true,
"priority": 15
}
}
Response
{
"id": "1920438292130",
"slug": "reset-password",
"category_id": "1920438291730",
"title": "Reset your password",
"description": "Recover access when you forget your password.",
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email and follow the link.",
"is_public": true,
"priority": 15
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.replaceOneById",
"params": {
"id": "1920438292130",
"document": {
"slug": "reset-password",
"category_id": "1920438291730",
"title": "Reset your password",
"description": "Recover access when you forget your password.",
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email and follow the link.",
"is_public": true,
"priority": 15
}
},
"id": 14
}
Response
{
"jsonrpc": "2.0",
"result": {
"id": "1920438292130",
"slug": "reset-password",
"category_id": "1920438291730",
"title": "Reset your password",
"description": "Recover access when you forget your password.",
"body": "## How to reset\n\n1. Go to the sign-in page.\n2. Click **Forgot password?**.\n3. Enter your email and follow the link.",
"is_public": true,
"priority": 15
},
"id": 14
}
update
Batch update multiple articles in a single transaction (all-or-nothing). See Batch operations.
HTTP
Request
PATCH /v1/help/articles
Authorization: Bearer <token>
Content-Type: application/json
{
"items": [
{ "id": "1920438292100", "document": { "priority": 20 } },
{ "id": "1920438292110", "document": { "is_public": true } }
]
}
Response
{
"affected": 2,
"items": [
{ "id": "1920438292100", "priority": 20 },
{ "id": "1920438292110", "is_public": true }
]
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.update",
"params": {
"items": [
{ "id": "1920438292100", "document": { "priority": 20 } },
{ "id": "1920438292110", "document": { "is_public": true } }
]
},
"id": 15
}
Response
{
"jsonrpc": "2.0",
"result": {
"affected": 2,
"items": [
{ "id": "1920438292100", "priority": 20 },
{ "id": "1920438292110", "is_public": true }
]
},
"id": 15
}
deleteOneById
Delete an article. All translations and author attributions belonging to it are deleted with it (cascade).
HTTP
Request
DELETE /v1/help/articles/1920438292130
Authorization: Bearer <token>
Response
{
"id": "1920438292130",
"slug": "reset-password",
"title": "Reset your password"
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.deleteOneById",
"params": {
"id": "1920438292130"
},
"id": 16
}
Response
{
"jsonrpc": "2.0",
"result": {
"id": "1920438292130",
"slug": "reset-password",
"title": "Reset your password"
},
"id": 16
}
delete
Batch delete articles in a single transaction (all-or-nothing). See Batch operations.
HTTP
Request
DELETE /v1/help/articles
Authorization: Bearer <token>
Content-Type: application/json
{
"items": [
{ "id": "1920438292100" },
{ "id": "1920438292110" }
]
}
Response
{
"affected": 2,
"items": [
{ "id": "1920438292100" },
{ "id": "1920438292110" }
]
}
WebSocket
Request
{
"jsonrpc": "2.0",
"method": "help.articles.delete",
"params": {
"items": [
{ "id": "1920438292100" },
{ "id": "1920438292110" }
]
},
"id": 17
}
Response
{
"jsonrpc": "2.0",
"result": {
"affected": 2,
"items": [
{ "id": "1920438292100" },
{ "id": "1920438292110" }
]
},
"id": 17
}