Categories
Group questions into categories. Categories carry an order, a slug, and an optional description.
Updated 2026-06-14
Categories group questions. Every question belongs to exactly one category. Categories carry a slug (URL-safe identifier), a display name, an explicit order for sort, and an optional description.
List
curl https://api.thefaq.app/api/v1/acme/categories \
-H "Authorization: Bearer $FAQAPP_API_KEY"
Query params:
limit(1–100, default 50)cursor(opaque, from the previous response'smeta.pagination.cursor)q(text search across name + description)
Response:
{
"data": [
{
"id": "cat_billing",
"slug": "billing",
"name": "Billing",
"description": "Subscriptions, invoices, refunds.",
"order": 1,
"questionCount": 8,
"createdAt": "2026-04-01T10:00:00Z",
"updatedAt": "2026-05-19T14:23:00Z"
}
],
"meta": { "pagination": { "limit": 50, "cursor": null, "hasMore": false } }
}
Get by id or slug
curl https://api.thefaq.app/api/v1/acme/categories/billing \
-H "Authorization: Bearer $FAQAPP_API_KEY"
Accepts either id (cat_billing) or slug (billing).
Create
curl -X POST https://api.thefaq.app/api/v1/acme/categories \
-H "Authorization: Bearer $FAQAPP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Billing",
"description": "Subscriptions, invoices, refunds.",
"order": 1
}'
Body:
name(string, required): display name; slug auto-generated from thisslug(string, optional): override the auto-slugdescription(string, optional): shown on the category landing in default renderersorder(integer, optional, default 0): lower numbers sort first
Required scope: write.
Update
curl -X PATCH https://api.thefaq.app/api/v1/acme/categories/billing \
-H "Authorization: Bearer $FAQAPP_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "order": 2, "description": "Updated description." }'
Any field accepted by create can be patched. Slug changes do not redirect old URLs — plan ahead.
Required scope: write.
Delete
curl -X DELETE https://api.thefaq.app/api/v1/acme/categories/billing \
-H "Authorization: Bearer $FAQAPP_API_KEY"
Returns 204 No Content. Categories with questionCount > 0 cannot be deleted — move or delete the questions first, or pass ?force=true to move them to the default category atomically.
Required scope: write.
Merge
Fold one category into another. The source's child categories are re-parented to the target, the source's questions are re-assigned to the target, and the source is optionally soft-deleted. Every statement is org-scoped, so ids from another organization are rejected.
curl -X POST https://api.thefaq.app/api/v1/acme/categories/merge \
-H "Authorization: Bearer $FAQAPP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sourceId": "cat_legacy",
"targetId": "cat_billing",
"deleteSource": true
}'
Body:
sourceId(string, required): the category to merge from. Must differ fromtargetId.targetId(string, required): the category to merge into.deleteSource(boolean, optional, default false): soft-delete the source after moving its contents.
Response:
{
"data": {
"childrenMoved": 2,
"questionsMoved": 14,
"sourceDeleted": true
}
}
Required scope: admin.
Reorder
Set the sort order of a set of categories in one request. Pass the ids in the order you want them — index 0 becomes order 0, index 1 becomes 1, and so on. Categories not in the list keep their current order.
curl -X POST https://api.thefaq.app/api/v1/acme/categories/reorder \
-H "Authorization: Bearer $FAQAPP_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "ids": ["cat_billing", "cat_account", "cat_legacy"] }'
Body:
ids(string[], required, 1–1000): category ids in the desired order. Every id must belong to this organization, or the whole request is rejected withvalidation_error.
Response:
{ "data": { "updated": 3 } }
Required scope: write.
Audit log
Every create/update/delete writes an audit entry. Retrieve recent ones:
curl https://api.thefaq.app/api/v1/acme/categories/audit \
-H "Authorization: Bearer $FAQAPP_API_KEY"
Returns the last 100 mutations with actor (member id or API-key fingerprint), action, before/after diffs, and timestamps.
Error codes
category_not_found(404): id or slug doesn't exist in this orgvalidation_failed(400): required field missing or wrong typeslug_conflict(409): slug already taken in this orgcategory_not_empty(409): delete attempted on category with questions — use?force=trueor move questions firstplan_limit_reached(402): org hit its category cap