Create a category
const url = 'https://flow.work.optidata.cloud/api/categories';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"Onboarding","description":"Everything a new hire needs in the first month.","visibility":"restricted"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://flow.work.optidata.cloud/api/categories \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "Onboarding", "description": "Everything a new hire needs in the first month.", "visibility": "restricted" }'Creates a category owned by the caller, together with its Overview
page. The name must be unique within the company; its slug is derived
from it.
visibility is required here — the request currently fails with a
server error when it is omitted. On update it stays optional.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
Category name, unique within the company.
Who can see a category. restricted: only the people and groups it is
shared with. internal: everyone in the company. public: anyone with the
link, including people who are not signed in.
Examples
{ "name": "Onboarding", "description": "Everything a new hire needs in the first month.", "visibility": "restricted"}Responses
Section titled “ Responses ”The category was created.
object
URL-friendly form of the name.
Who can see a category. restricted: only the people and groups it is
shared with. internal: everyone in the company. public: anyone with the
link, including people who are not signed in.
Shortcut for visibility == public.
Short public identifier of the category.
Id of the user who owns the category, when it has one.
Set when the category mirrors a group: it is shared with the group’s members, and its name and description follow the group’s.
Identifier of the company the category belongs to.
Set when the category is in the trash.
Examples
{ "name": "Onboarding", "slug": "onboarding", "cuid": "7f3c2a10-5b8e-4d21-9c6a-0e4f1b2d3c4a", "description": "Everything a new hire needs in the first month.", "visibility": "restricted", "group_id": null, "user_id": 20, "identifier": "jYpV3A", "updated_at": "2026-10-19T13:50:38.000000Z", "created_at": "2026-10-19T13:50:38.000000Z", "id": 993, "is_public": false}No authentication key was sent.
Authentication failures use an error key rather than message.
object
Examples
No bearer token sent
{ "error": "JWT passport exception: Missing bearer token in request"}The authentication key is expired or not recognised. Get a fresh one and retry.
Authentication failures use an error key rather than message.
object
Examples
{ "error": "JWT passport expired: Passport expired"}The body failed validation — for instance, a category with that name already exists.
object
The first validation message.
Validation messages keyed by field name.
object
Examples
{ "message": "A category with this name already exists.", "errors": { "name": [ "A category with this name already exists." ] }}