Knowledge Base Categories

Base URL: https://api.cornerspot.net

Authentication: requests use a bearer token, for example Authorization: Bearer YOUR_API_KEY.

List help-center categories

GET /c/api/v1/help_center/categories

Returns a paginated list of the team's knowledge-base categories. Supports full-text search over title and description, a status filter for draft (no published_at) vs live (has published_at) categories, and a parent_id filter for navigating the one-level category tree (top-level categories vs the children of a given parent). Requires the kb_read scope and the Knowledge Base module.

Query parameters

FIELDTYPEDESCRIPTION
querystringFull-text search over category title and description.
qstringAlias for query.
statusstring
one of draft, live
Filter by publication status: draft (no published_at) or live (published_at present). Omit for all.
parent_idstringFilter by parent. Pass a category id to return that category's children, or none (also null/top_level) to return only top-level categories. Omit to return categories at every level.
pageinteger1-based page number.
per_pageintegerPage size (1–100, default 25).

Code samples

curl --request GET \
  --url 'https://api.cornerspot.net/c/api/v1/help_center/categories' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const data = await response.json();
console.log(data);
import json
import urllib.request

url = "https://api.cornerspot.net/c/api/v1/help_center/categories"
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
}

request = urllib.request.Request(url, headers=headers, method="GET")

with urllib.request.urlopen(request) as response:
    data = json.loads(response.read().decode("utf-8"))
    print(data)
require "json"
require "net/http"

uri = URI("https://api.cornerspot.net/c/api/v1/help_center/categories")

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts JSON.parse(response.body)
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/help_center/categories',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);

Responses

STATUSDESCRIPTION
200 OKa page of categories
401 Unauthorizedmissing or invalid API key
402 Payment Requiredteam's plan does not include the knowledge feature
403 Forbiddenthe key lacks the kb_read scope

Create a help-center category

POST /c/api/v1/help_center/categories

Creates a new knowledge-base category for the team. title is required. If slug is omitted it is auto-generated from title. icon_kind defaults to lucide. published_at defaults to the current time.

Pass parent_category_id to nest the category under a top-level one. Categories nest at most one level deep: the parent must itself be top-level, otherwise the request returns 422. Requires the kb_write scope and the Knowledge Base module.

Request body

FIELDTYPEDESCRIPTION
categoryobject
category.titlestring · requiredRequired. Category title, max 120 characters.
category.descriptionstringOptional description, max 500 characters.
category.slugstringURL slug (lowercase alphanumeric + hyphens). Auto-generated from title if omitted.
category.icon_kindstring
one of lucide, media
Icon type. Defaults to lucide.
category.icon_namestringLucide icon name (required when icon_kind is lucide).
category.icon_asset_idstringAsset id for the icon image (required when icon_kind is media).
category.parent_category_idstringOptional. Id of a top-level category to nest under. The parent must be top-level (one level of nesting max), else 422.
category.published_atstringPublication timestamp. Defaults to now.

Code samples

curl --request POST \
  --url 'https://api.cornerspot.net/c/api/v1/help_center/categories' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{
  "category": {
    "title": "string",
    "description": "string",
    "slug": "string",
    "icon_kind": "lucide",
    "icon_name": "string",
    "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "published_at": "2026-01-15T09:30:00Z"
  }
}'
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    "category": {
      "title": "string",
      "description": "string",
      "slug": "string",
      "icon_kind": "lucide",
      "icon_name": "string",
      "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "published_at": "2026-01-15T09:30:00Z"
    }
  })
});

const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    "category": {
      "title": "string",
      "description": "string",
      "slug": "string",
      "icon_kind": "lucide",
      "icon_name": "string",
      "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "published_at": "2026-01-15T09:30:00Z"
    }
  })
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const data = await response.json();
console.log(data);
import json
import urllib.request

url = "https://api.cornerspot.net/c/api/v1/help_center/categories"
payload = json.dumps({
  "category": {
    "title": "string",
    "description": "string",
    "slug": "string",
    "icon_kind": "lucide",
    "icon_name": "string",
    "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "published_at": "2026-01-15T09:30:00Z"
  }
}).encode("utf-8")
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_API_KEY",
}

request = urllib.request.Request(url, data=payload, headers=headers, method="POST")

with urllib.request.urlopen(request) as response:
    data = json.loads(response.read().decode("utf-8"))
    print(data)
require "json"
require "net/http"

uri = URI("https://api.cornerspot.net/c/api/v1/help_center/categories")

request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer YOUR_API_KEY"
request.body = JSON.generate({
  "category": {
    "title": "string",
    "description": "string",
    "slug": "string",
    "icon_kind": "lucide",
    "icon_name": "string",
    "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "published_at": "2026-01-15T09:30:00Z"
  }
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts JSON.parse(response.body)
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/help_center/categories',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer YOUR_API_KEY',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'category' => [
        'title' => 'string',
        'description' => 'string',
        'slug' => 'string',
        'icon_kind' => 'lucide',
        'icon_name' => 'string',
        'icon_asset_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
        'parent_category_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
        'published_at' => '2026-01-15T09:30:00Z',
    ],
]),
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);

Responses

STATUSDESCRIPTION
201 Createdcreated
401 Unauthorizedmissing or invalid API key
402 Payment Requiredteam's plan does not include the knowledge feature
403 Forbiddenthe key lacks kb_write scope
422 Unprocessable Contentvalidation errors (e.g. missing title, invalid icon, non-top-level parent)

Get a help-center category

GET /c/api/v1/help_center/categories/{id}

Returns a single category by id. Requires kb_read and the Knowledge Base module.

Path parameters

FIELDTYPEDESCRIPTION
idstring · requiredCategory id.

Code samples

curl --request GET \
  --url 'https://api.cornerspot.net/c/api/v1/help_center/categories/abc123' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/abc123', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/abc123', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const data = await response.json();
console.log(data);
import json
import urllib.request

url = "https://api.cornerspot.net/c/api/v1/help_center/categories/abc123"
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
}

request = urllib.request.Request(url, headers=headers, method="GET")

with urllib.request.urlopen(request) as response:
    data = json.loads(response.read().decode("utf-8"))
    print(data)
require "json"
require "net/http"

uri = URI("https://api.cornerspot.net/c/api/v1/help_center/categories/abc123")

request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts JSON.parse(response.body)
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/help_center/categories/abc123',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);

Responses

STATUSDESCRIPTION
200 OKthe category
401 Unauthorizedmissing or invalid API key
404 Not Foundno such category in this team

Update a help-center category

PATCH /c/api/v1/help_center/categories/{id}

Updates a help-center category. Note: position cannot be changed here — use the reorder endpoint to resequence categories. Requires kb_write and the Knowledge Base module.

Path parameters

FIELDTYPEDESCRIPTION
idstring · requiredCategory id.

Request body

FIELDTYPEDESCRIPTION
categoryobject
category.titlestring
category.descriptionstring
category.slugstring
category.icon_kindstring
one of lucide, media
category.icon_namestring
category.icon_asset_idstring
category.parent_category_idstringNest under a top-level category, or null to promote back to top-level. Must reference a top-level category; a category that already has children can't be nested.
category.published_atstring

Code samples

curl --request PATCH \
  --url 'https://api.cornerspot.net/c/api/v1/help_center/categories/abc123' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{
  "category": {
    "title": "string",
    "description": "string",
    "slug": "string",
    "icon_kind": "lucide",
    "icon_name": "string",
    "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "published_at": "2026-01-15T09:30:00Z"
  }
}'
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/abc123', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    "category": {
      "title": "string",
      "description": "string",
      "slug": "string",
      "icon_kind": "lucide",
      "icon_name": "string",
      "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "published_at": "2026-01-15T09:30:00Z"
    }
  })
});

const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/abc123', {
  method: 'PATCH',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    "category": {
      "title": "string",
      "description": "string",
      "slug": "string",
      "icon_kind": "lucide",
      "icon_name": "string",
      "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
      "published_at": "2026-01-15T09:30:00Z"
    }
  })
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const data = await response.json();
console.log(data);
import json
import urllib.request

url = "https://api.cornerspot.net/c/api/v1/help_center/categories/abc123"
payload = json.dumps({
  "category": {
    "title": "string",
    "description": "string",
    "slug": "string",
    "icon_kind": "lucide",
    "icon_name": "string",
    "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "published_at": "2026-01-15T09:30:00Z"
  }
}).encode("utf-8")
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_API_KEY",
}

request = urllib.request.Request(url, data=payload, headers=headers, method="PATCH")

with urllib.request.urlopen(request) as response:
    data = json.loads(response.read().decode("utf-8"))
    print(data)
require "json"
require "net/http"

uri = URI("https://api.cornerspot.net/c/api/v1/help_center/categories/abc123")

request = Net::HTTP::Patch.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer YOUR_API_KEY"
request.body = JSON.generate({
  "category": {
    "title": "string",
    "description": "string",
    "slug": "string",
    "icon_kind": "lucide",
    "icon_name": "string",
    "icon_asset_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "parent_category_id": "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d",
    "published_at": "2026-01-15T09:30:00Z"
  }
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts JSON.parse(response.body)
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/help_center/categories/abc123',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer YOUR_API_KEY',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'category' => [
        'title' => 'string',
        'description' => 'string',
        'slug' => 'string',
        'icon_kind' => 'lucide',
        'icon_name' => 'string',
        'icon_asset_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
        'parent_category_id' => '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
        'published_at' => '2026-01-15T09:30:00Z',
    ],
]),
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);

Responses

STATUSDESCRIPTION
200 OKupdated — title changed and nested under a top-level parent
401 Unauthorizedmissing or invalid API key
403 Forbiddenthe key lacks kb_write scope
404 Not Foundno such category in this team
422 Unprocessable Contentvalidation errors (e.g. blank title, invalid slug, non-top-level parent)

Delete a help-center category

DELETE /c/api/v1/help_center/categories/{id}

Soft-deletes a help-center category. Returns 422 category_has_articles if the category still contains non-deleted articles — move or delete those articles first. Requires kb_write and the Knowledge Base module.

Path parameters

FIELDTYPEDESCRIPTION
idstring · requiredCategory id.

Code samples

curl --request DELETE \
  --url 'https://api.cornerspot.net/c/api/v1/help_center/categories/abc123' \
  --header 'Authorization: Bearer YOUR_API_KEY'
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/abc123', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/abc123', {
  method: 'DELETE',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY'
  }
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const data = await response.json();
console.log(data);
import json
import urllib.request

url = "https://api.cornerspot.net/c/api/v1/help_center/categories/abc123"
headers = {
    "Authorization": "Bearer YOUR_API_KEY",
}

request = urllib.request.Request(url, headers=headers, method="DELETE")

with urllib.request.urlopen(request) as response:
    data = json.loads(response.read().decode("utf-8"))
    print(data)
require "json"
require "net/http"

uri = URI("https://api.cornerspot.net/c/api/v1/help_center/categories/abc123")

request = Net::HTTP::Delete.new(uri)
request["Authorization"] = "Bearer YOUR_API_KEY"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts JSON.parse(response.body)
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/help_center/categories/abc123',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer YOUR_API_KEY',
    ],
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);

Responses

STATUSDESCRIPTION
204 No Contentdeleted
401 Unauthorizedmissing or invalid API key
403 Forbiddenthe key lacks kb_write scope
404 Not Foundno such category in this team
422 Unprocessable Contentcategory still contains articles

Reorder help-center categories

POST /c/api/v1/help_center/categories/reorder

Sets the position of every help-center category in one atomic operation. The ids array must contain exactly the ids of every category in the team — a partial or mismatched list returns 422 incomplete_reorder. Requires kb_write and the Knowledge Base module.

Request body

FIELDTYPEDESCRIPTION
ids[]array of string · requiredComplete ordered list of every category id in the team.

Code samples

curl --request POST \
  --url 'https://api.cornerspot.net/c/api/v1/help_center/categories/reorder' \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{
  "ids": [
    "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d"
  ]
}'
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/reorder', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    "ids": [
      "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d"
    ]
  })
});

const data = await response.json();
console.log(data);
// Node.js 18+ (native fetch)
const response = await fetch('https://api.cornerspot.net/c/api/v1/help_center/categories/reorder', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    "ids": [
      "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d"
    ]
  })
});

if (!response.ok) {
  throw new Error(`Request failed: ${response.status}`);
}

const data = await response.json();
console.log(data);
import json
import urllib.request

url = "https://api.cornerspot.net/c/api/v1/help_center/categories/reorder"
payload = json.dumps({
  "ids": [
    "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d"
  ]
}).encode("utf-8")
headers = {
    "Content-Type": "application/json",
    "Authorization": "Bearer YOUR_API_KEY",
}

request = urllib.request.Request(url, data=payload, headers=headers, method="POST")

with urllib.request.urlopen(request) as response:
    data = json.loads(response.read().decode("utf-8"))
    print(data)
require "json"
require "net/http"

uri = URI("https://api.cornerspot.net/c/api/v1/help_center/categories/reorder")

request = Net::HTTP::Post.new(uri)
request["Content-Type"] = "application/json"
request["Authorization"] = "Bearer YOUR_API_KEY"
request.body = JSON.generate({
  "ids": [
    "1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d"
  ]
})

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http|
  http.request(request)
end

puts JSON.parse(response.body)
<?php

$curl = curl_init();

curl_setopt_array($curl, [
    CURLOPT_URL => 'https://api.cornerspot.net/c/api/v1/help_center/categories/reorder',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => [
        'Content-Type: application/json',
        'Authorization: Bearer YOUR_API_KEY',
    ],
    CURLOPT_POSTFIELDS => json_encode([
    'ids' => [
        '1f2e3d4c-5b6a-4789-9c0d-1e2f3a4b5c6d',
    ],
]),
]);

$response = curl_exec($curl);
curl_close($curl);

$data = json_decode($response, true);
print_r($data);

Responses

STATUSDESCRIPTION
200 OKreordered — returns the full list in new order
401 Unauthorizedmissing or invalid API key
402 Payment Requiredteam's plan does not include the knowledge feature
403 Forbiddenthe key lacks kb_write scope
422 Unprocessable Contentincomplete reorder — ids do not match all team categories

Was this article helpful?