Use Cases Pricing Embeds API Sign in Get Started
Home

API Documentation

Use the REST API to programmatically manage your helpdesk content

Contents
Quick Start

Create a category and article in 3 steps

const API_KEY = "hdh_your_api_key";
const BASE_URL = "https://helpdesky.io/api/v1";

const headers = {
  "X-API-Key": API_KEY,
  "Content-Type": "application/json",
};

// 1. Create a category
const catRes = await fetch(`${BASE_URL}/categories`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    name: "Getting Started",
    description: "Help users get set up",
  }),
});
const { data: category } = await catRes.json();

// 2. Create an article in that category
const articleRes = await fetch(`${BASE_URL}/articles`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    title: "How to create your first project",
    content: "## Welcome\n\nFollow these steps to get started:\n\n1. Click **New Project**\n2. Enter a name\n3. Choose a template\n\nThat's it!",
    categoryId: category.id,
    published: true,
  }),
});
const { data: article } = await articleRes.json();
console.log("Created:", article.title);
Authentication

All API requests require an API key sent via the X-API-Key header. Generate your API key from your dashboard under Settings > API Integration.

curl -X GET https://helpdesky.io/api/v1/categories \
  -H "X-API-Key: hdh_your_api_key_here"

Base URL: https://helpdesky.io/api/v1

Content Type: application/json

Categories

CRUD operations for organising articles into categories

GET /api/v1/categories

List all categories in your helpdesk

curl -X GET https://helpdesky.io/api/v1/categories \
  -H "X-API-Key: hdh_your_api_key"
{
  "data": [
    {
      "id": "abc123",
      "name": "Getting Started",
      "slug": "getting-started",
      "description": "Introductory guides",
      "icon": "folder",
      "order": 0
    }
  ]
}
POST /api/v1/categories

Create a new category

{
  "name": "Getting Started",      // required
  "description": "Intro guides",  // optional
  "icon": "book-open"              // optional, default: "folder"
}
curl -X POST https://helpdesky.io/api/v1/categories \
  -H "X-API-Key: hdh_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Getting Started", "description": "Introductory guides"}'
{
  "data": {
    "id": "abc123",
    "name": "Getting Started",
    "slug": "getting-started",
    "description": "Introductory guides",
    "icon": "folder",
    "order": 0
  }
}
PATCH /api/v1/categories/:id

Update a category. Only include the fields you want to change.

{
  "name": "New Name",             // optional
  "description": "Updated desc",  // optional
  "icon": "star",                  // optional
  "order": 1                       // optional
}
curl -X PATCH https://helpdesky.io/api/v1/categories/CATEGORY_ID \
  -H "X-API-Key: hdh_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"name": "Updated Name"}'
{
  "data": {
    "id": "abc123",
    "name": "Updated Name",
    "slug": "getting-started",
    "description": "Introductory guides",
    "icon": "folder",
    "order": 0
  }
}
DELETE /api/v1/categories/:id

Delete a category and all its articles

curl -X DELETE https://helpdesky.io/api/v1/categories/CATEGORY_ID \
  -H "X-API-Key: hdh_your_api_key"
{
  "data": {
    "success": true
  }
}
Articles

CRUD operations for managing helpdesk articles

GET /api/v1/articles

List all articles. Optionally filter by category using the categoryId query parameter.

curl -X GET "https://helpdesky.io/api/v1/articles?categoryId=CATEGORY_ID" \
  -H "X-API-Key: hdh_your_api_key"
{
  "data": [
    {
      "id": "def456",
      "title": "How to reset your password",
      "slug": "how-to-reset-your-password",
      "content": "## Steps\n\n1. Click **Forgot Password**...",
      "excerpt": "Learn how to reset your password",
      "published": true,
      "categoryId": "abc123",
      "order": 0
    }
  ]
}
POST /api/v1/articles

Create a new article. Content should be in Markdown format.

{
  "title": "How to reset your password",  // required
  "content": "## Steps\n\n1. Click...",    // required, Markdown
  "slug": "reset-password",                // optional, auto-generated from title if omitted
  "excerpt": "Short summary",               // optional
  "categoryId": "abc123",                   // optional
  "published": true,                         // optional, default: false
  "numberHeadings": true                     // optional, default: false — numbers H2 headings
}
curl -X POST https://helpdesky.io/api/v1/articles \
  -H "X-API-Key: hdh_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "How to reset your password",
    "content": "## Steps\n\n1. Click **Forgot Password**\n2. Enter your email\n3. Check your inbox",
    "categoryId": "CATEGORY_ID",
    "published": true
  }'
{
  "data": {
    "id": "def456",
    "title": "How to reset your password",
    "slug": "reset-password",
    "content": "## Steps\n\n1. Click **Forgot Password**...",
    "excerpt": null,
    "published": true,
    "numberHeadings": false,
    "categoryId": "abc123",
    "order": 0
  }
}
PATCH /api/v1/articles/:id

Update an article. Only include the fields you want to change. Changing the slug on a published article automatically creates a 301 redirect from the old URL.

{
  "title": "Updated Title",       // optional
  "content": "New content...",     // optional, Markdown
  "slug": "new-url-handle",       // optional — auto-redirect created for published articles
  "excerpt": "Updated summary",   // optional
  "categoryId": "abc123",         // optional
  "published": true,               // optional
  "numberHeadings": true,          // optional — numbers H2 headings
  "order": 2                       // optional
}
curl -X PATCH https://helpdesky.io/api/v1/articles/ARTICLE_ID \
  -H "X-API-Key: hdh_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"published": true}'
{
  "data": {
    "id": "def456",
    "title": "How to reset your password",
    "slug": "new-url-handle",
    "content": "## Steps...",
    "published": true,
    "numberHeadings": true,
    "categoryId": "abc123",
    "order": 0
  }
}
DELETE /api/v1/articles/:id

Delete an article permanently

curl -X DELETE https://helpdesky.io/api/v1/articles/ARTICLE_ID \
  -H "X-API-Key: hdh_your_api_key"
{
  "data": {
    "success": true
  }
}
Images

Upload images to use in article content

POST /api/v1/images

Upload an image file. Returns a URL you can embed in article content using HTML or Markdown (see format options below). Maximum file size is 5MB. Allowed types: JPG, PNG, GIF, WebP, SVG.

Send a multipart/form-data request with the image in a field named image.

curl -X POST https://helpdesky.io/api/v1/images \
  -H "X-API-Key: hdh_your_api_key" \
  -F "image=@/path/to/screenshot.png"
{
  "url": "/api/images/uploads/USER_ID/abc123-screenshot.png",
  "filename": "screenshot.png",
  "size": 245760,
  "contentType": "image/png"
}
Using images in articles

Use the returned url in your article content. There are two formats you can use:

Use an HTML <img> tag to control the display size with width and/or height attributes. This is the same format used by the dashboard visual editor.

<img src="/api/images/uploads/USER_ID/abc123-screenshot.png" width="400" />

Standard Markdown image syntax. Simple, but the image always displays at its full original size — there is no way to set dimensions.

![Screenshot](/api/images/uploads/USER_ID/abc123-screenshot.png)

Tip: We recommend HTML for most use cases — it gives you full control over how large images appear in your articles. Both formats are supported anywhere in your article content and can be mixed freely.

Error Responses

All errors return a JSON object with an error field:

{
  "error": "Missing X-API-Key header"
}
{
  "error": "Title is required"
}
{
  "error": "Category not found"
}
{
  "error": "Rate limit exceeded. Please try again later."
}
{
  "error": "Internal server error"
}
Markdown Formatting

Supported syntax for article content

Article content uses Markdown. In addition to standard syntax (headings, bold, italic, lists, links, images, code blocks), we support:

Use pipe syntax to create tables. The first row becomes the header.

| Feature     | Status    | Notes             |
| ----------- | --------- | ----------------- |
| Markdown    | Supported | Full GFM syntax   |
| Tables      | Supported | Auto-styled       |
| Callouts    | Supported | info/warning/danger |

Highlight important information with callout blocks using blockquote syntax:

> [!info]
> This is an informational note.

> [!warning]
> Be careful with this setting.

> [!danger]
> This action cannot be undone.

Paste a YouTube URL on its own line to auto-embed the video:

https://www.youtube.com/watch?v=VIDEO_ID
Notes

Slugs

Slugs are auto-generated from the article title or category name if not provided, but you can set a custom slug when creating an article or category via POST. You can also change the slug later with PATCH. If you change the slug on a published article, a 301 redirect is automatically created from the old URL to the new one.

Public URLs

Article slugs determine the public URL of each article. The URL format depends on whether you use a custom domain:

Path-based (default): https://helpdesky.io/help/{helpdesk-slug}/{article-slug}

Custom domain: https://{your-domain}/{article-slug}

On custom domains, articles are served directly at the root. The /articles path (without a slug) is a separate page that lists all published articles.

Pagination

The API does not currently paginate results. All categories and articles are returned in a single response.

Filtering

Use the categoryId query parameter on GET /api/v1/articles to filter articles by category.

Rate Limiting

The API is limited to 60 requests per minute per API key. If you exceed this limit, you'll receive a 429 status code. Rate limit headers (RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset) are included in every response.

Category Icons

The following icon values are available for categories:

folder file-text book-open lightbulb help-circle settings zap users

The default icon is folder if none is specified.