> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://help.crisp.chat/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# How to migrate to the new Knowledge Base API

On September 22, 2026, Crisp migrated all workspaces to a new Knowledge Base system with a new interface and a new API. All existing Knowledge Base content was automatically converted during this migration.

Your articles remain available, but integrations must now use the new tree-based API to create or update them. The legacy article API no longer accepts write operations. Until your API calls are migrated, `website_cannot_write_to_legacy_helpdesk` errors are expected.

## Update your integration

Replace the legacy endpoint:

```text
PATCH /v1/website/{website_id}/helpdesk/locale/{locale}/article/{article_id}
```

The new Knowledge Base identifies articles by their tree path. You can list the article tree to find that path:

```text
GET /v1/website/{website_id}/helpdesk/tree/list/{locale}/articles/1
```

## What is a tree path?

A tree path is the location of an article inside your Knowledge Base hierarchy. It is relative to the locale and content type already present in the API URL.

An article path includes its category, any optional section, and the article filename with its `.md` extension.

```text
orders/shipping-policy.md
```

This path identifies the `shipping-policy.md` article inside the `orders` category.

```text
orders/delivery/shipping-policy.md
```

This path identifies the article inside the `delivery` section of the `orders` category.

In this example:

- `orders` is the category slug
- `delivery` is the section slug
- `shipping-policy.md` is the article filename

The tree path is not the legacy article ID or the public article URL. Build it by joining the `slug` values returned by the tree list endpoint. For example, the `orders` directory and its `shipping-policy.md` child produce `orders/shipping-policy.md`.

## Map a legacy article ID to a tree path

If your integration still stores the old `article_id`, resolve it to a tree path:

```text
GET /v1/website/{website_id}/helpdesk/page/entity/{locale}/articles/{article_id}
```

The response includes tree_path, which you can reuse on the new write endpoints:

```json
{
  "entity_id": "01959c8b-0c6e-7e4c-8dfb-6e0a420ac990",
  "title": "Shipping policy",
  "tree_path": "orders/shipping-policy.md",
  "url": "https://acme.crisp.help/en/article/shipping-policy-xxxxx/"
}
```

## Using the Node.js wrapper

Install the official [`crisp-api`](https://github.com/crisp-im/node-crisp-api) package:

```shell
npm install --save crisp-api
```

Authenticate with a user token, find the article path, then update its content and metadata:

```javascript
const { Crisp } = require("crisp-api");

const CrispClient = new Crisp();

CrispClient.authenticateTier(
  "user",
  process.env.CRISP_TOKEN_IDENTIFIER,
  process.env.CRISP_TOKEN_KEY
);

const websiteID = "YOUR_WEBSITE_ID";
const locale = "en";
const contentType = "articles";

async function updateArticle() {
  const entries = await CrispClient.website.listHelpdeskTree(
    websiteID, locale, contentType, 1, null, "Shipping policy"
  );

  console.log(entries);

  // Build this path from the slugs returned above.
  const path = "orders/shipping-policy.md";
  const content = "# Shipping policy\n\nYour updated article content.";

  await CrispClient.website.saveHelpdeskTreeContent(
    websiteID, locale, contentType, path, content
  );

  await CrispClient.website.updateHelpdeskTreeMetadata(
    websiteID, locale, contentType, path, {
      format: "articles",
      title: "Shipping policy",
      state: {
        published: true
      }
    }
  );
}

updateArticle().catch(console.error);
```

`saveHelpdeskTreeContent` updates the article body. `updateHelpdeskTreeMetadata` updates fields such as the title, description, author, and publication state.

## Using the REST API directly

Then update the article content:

```text
PUT /v1/website/{website_id}/helpdesk/tree/content/{locale}/articles/{path}
```

For example:

```text
PUT /v1/website/{website_id}/helpdesk/tree/content/en/articles/orders/shipping-policy.md
```

```json
{
  "content": "Your article content in Markdown"
}
```

To update the title, description, or publication state, use the metadata endpoint:

```text
PATCH /v1/website/{website_id}/helpdesk/tree/metadata/{locale}/articles/{path}
```

For example:

```text
PATCH /v1/website/{website_id}/helpdesk/tree/metadata/en/articles/orders/shipping-policy.md
```

```json
{
  "format": "articles",
  "title": "Your article title",
  "state": {
    "published": true
  }
}
```

Content and metadata are updated through separate requests. Keep using your existing `website_id` and locale, and replace `{path}` with the article path returned by the tree API.

See the [Crisp REST API reference](https://docs.crisp.chat/references/rest-api/v1/) for authentication requirements and complete request schemas.