# Articles

> Articles are the building blocks of your Knowledge Base. Create, list, update, and delete the content your AI Agent uses to answer questions.

Articles are the building blocks of your AI Agent's Knowledge Base. Each article represents a piece of knowledge — a help page, FAQ entry, product description, or any content your AI should know about.

There are three article types: **Articles** (full documents with title and body), **Paragraphs** (short standalone text entries), and **URL articles** (automatically created when importing web content). You can create articles manually via the API, import them from websites using [Import External Content](/api-reference/knowledge-base/import-external-content/), upload files via [File Upload](/api-reference/knowledge-base/file-upload/), or sync from [Intercom](/api-reference/knowledge-base/intercom-knowledge-base/).

After creating or updating articles, remember to [retrain the Knowledge Base](/api-reference/knowledge-base/#retrain-knowledge-base) for changes to take effect.

## Create Article

**Scope: write_all**

`POST https://app.quickchat.ai/v1/api/knowledge_base/articles/`

**Request Body**

| Parameter | Description |
|-----------|-------------|
| `content` <br/> string, required | Article content |
| `type` <br/> string | `"Article"` (default) or `"Paragraph"` |
| `title` <br/> string | Article title |

:::note[Article Types]
- **`"Article"`** — A full knowledge base document with title and content. Use for FAQ entries, help articles, product descriptions.
- **`"Paragraph"`** — A short standalone text entry without a title. Use for brief facts, one-liner answers, quick reference data.
- **`"URL"`** (read-only) — Created automatically when content is imported from a website. Contains the scraped page content with the source URL. Cannot be set on creation.
:::

**Shell**

```shell
curl -X POST https://app.quickchat.ai/v1/api/knowledge_base/articles/ \
  -H 'Authorization: Bearer <API_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{
  "content": "Our return policy allows returns within 30 days.",
  "title": "Return Policy"
}'
```

**Python**

```python
import requests

response = requests.post(
    url="https://app.quickchat.ai/v1/api/knowledge_base/articles/",
    headers={"Authorization": "Bearer <API_TOKEN>"},
    json={
        "content": "Our return policy allows returns within 30 days.",
        "title": "Return Policy",
    },
)
data = response.json()
```

**Response** `201 Created`

```json
{
  "id": 1234,
  "article_id": "abc-123",
  "type": "Article",
  "title": "Return Policy",
  "description": "",
  "content": "Our return policy allows returns within 30 days.",
  "state": "draft",
  "deploy_state": "draft",
  "version": null,
  "max_available_version": null,
  "url": null,
  "tags": [],
  "created_timestamp": "2026-01-15",
  "last_modified_timestamp": "2026-01-15",
  "downloaded_timestamp": "2026-01-15",
  "last_updated_timestamp": "2026-01-15",
  "last_updated_from_external_source_timestamp": null
}
```

| Field | Description |
|-------|-------------|
| `id` <br/> integer | Article numeric ID. This is the canonical identifier used in all URL paths |
| `article_id` <br/> string | Legacy string identifier. May be empty — use `id` instead |
| `type` <br/> string | `"Article"`, `"Paragraph"`, or `"URL"` |
| `title` <br/> string | Article title |
| `description` <br/> string | Article description |
| `content` <br/> string | Article content |
| `deploy_state` <br/> string | `"draft"` or `"published"` — controls article visibility |
| `state` <br/> string | Internal processing status (see note below) |
| `version` <br/> integer or null | Current version number |
| `max_available_version` <br/> integer or null | Highest available version |
| `url` <br/> string or null | Source URL (for URL-type articles) |
| `tags` <br/> array of strings | Associated tags |
| `created_timestamp` <br/> string | Creation date |
| `last_modified_timestamp` <br/> string | Last modification date |
| `downloaded_timestamp` <br/> string | Download date |
| `last_updated_timestamp` <br/> string | Last update date |
| `last_updated_from_external_source_timestamp` <br/> string or null | Last external source update |

:::note[Understanding Article States]
Articles have two state fields:
- **`deploy_state`**: Controls whether the article is a `"draft"` or `"published"`. This is the primary field you should use to manage article visibility.
- **`state`**: Reflects the internal processing status. For most API users, this field can be ignored — it tracks backend processing steps and may show values like `"done"` or `"published"`.
:::

## List Articles

**Scope: read_all**

`GET https://app.quickchat.ai/v1/api/knowledge_base/articles/`

**Query Parameters**

| Parameter | Description |
|-----------|-------------|
| `limit` <br/> integer | Items per page |
| `offset` <br/> integer | Items to skip |
| `types` <br/> string | Filter by type: `Article`, `Paragraph`, `URL` |
| `tags` <br/> string | Filter by tag |
| `url` <br/> string | Filter by URL |
| `title` <br/> string | Filter by title |
| `query` <br/> string | Search by content |

**Shell**

```shell
curl 'https://app.quickchat.ai/v1/api/knowledge_base/articles/?limit=10&offset=0' \
  -H 'Authorization: Bearer <API_TOKEN>'
```

**Python**

```python
import requests

response = requests.get(
    url="https://app.quickchat.ai/v1/api/knowledge_base/articles/",
    headers={"Authorization": "Bearer <API_TOKEN>"},
    params={"limit": 10, "offset": 0},
)
data = response.json()
```

**Response** `200 OK`

```json
{
  "items": [
    {
      "id": 1234,
      "article_id": "abc-123",
      "type": "Article",
      "title": "Return Policy",
      "description": "",
      "state": "published",
      "deploy_state": "published",
      "version": 1,
      "max_available_version": 1,
      "url": null,
      "tags": ["policies"],
      "created_timestamp": "2026-01-15",
      "last_modified_timestamp": "2026-01-15",
      "downloaded_timestamp": "2026-01-15",
      "last_updated_timestamp": "2026-01-15",
      "last_updated_from_external_source_timestamp": null
    }
  ],
  "offset": 0,
  "limit": 10,
  "count": 1
}
```

:::note
The list response does **not** include the `content` field. Use [Get Article](/api-reference/knowledge-base/articles/#get-article) to retrieve the full content of a specific article.
:::

## Get Article

**Scope: read_all**

`GET https://app.quickchat.ai/v1/api/knowledge_base/articles/{article_id}`

**Shell**

```shell
curl https://app.quickchat.ai/v1/api/knowledge_base/articles/1234 \
  -H 'Authorization: Bearer <API_TOKEN>'
```

**Python**

```python
import requests

response = requests.get(
    url="https://app.quickchat.ai/v1/api/knowledge_base/articles/1234",
    headers={"Authorization": "Bearer <API_TOKEN>"},
)
data = response.json()
```

**Response** `200 OK` — Returns the full article object (same schema as [Create Article](/api-reference/knowledge-base/articles/#create-article) response), including the `content` field.

## Update Article

**Scope: write_all**

`PATCH https://app.quickchat.ai/v1/api/knowledge_base/articles/{article_id}`

**Request Body**

| Parameter | Description |
|-----------|-------------|
| `content` <br/> string | Updated article content |
| `title` <br/> string | Updated title |
| `tags` <br/> array of strings | Updated tags |
| `save_mode` <br/> string | `"draft"` (default) or `"publish"` |

:::caution
The `save_mode: "draft"` option only sets the `deploy_state` flag — it does **not** prevent the article content from being used by the AI once the Knowledge Base is retrained. For programmatic workflows, use `save_mode: "publish"` and trigger a [retrain](/api-reference/knowledge-base/#retrain-knowledge-base) when you're ready for changes to take effect.
:::

**Shell**

```shell
curl -X PATCH https://app.quickchat.ai/v1/api/knowledge_base/articles/1234 \
  -H 'Authorization: Bearer <API_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '{
  "title": "Updated Return Policy",
  "content": "Returns accepted within 60 days.",
  "save_mode": "publish"
}'
```

**Python**

```python
import requests

response = requests.patch(
    url="https://app.quickchat.ai/v1/api/knowledge_base/articles/1234",
    headers={"Authorization": "Bearer <API_TOKEN>"},
    json={
        "title": "Updated Return Policy",
        "content": "Returns accepted within 60 days.",
        "save_mode": "publish",
    },
)
data = response.json()
```

**Response** `200 OK` — Returns the updated article object.

## Delete Articles

Delete one or more articles by ID.

**Scope: write_all**

`DELETE https://app.quickchat.ai/v1/api/knowledge_base/articles/`

**Request Body** — JSON array of article IDs.

**Shell**

```shell
curl -X DELETE https://app.quickchat.ai/v1/api/knowledge_base/articles/ \
  -H 'Authorization: Bearer <API_TOKEN>' \
  -H 'Content-Type: application/json' \
  -d '[1234, 5678]'
```

**Python**

```python
import requests

response = requests.delete(
    url="https://app.quickchat.ai/v1/api/knowledge_base/articles/",
    headers={"Authorization": "Bearer <API_TOKEN>"},
    json=[1234, 5678],
)
```

**Response** `200 OK`

## Search Articles

Search through article content with text matching.

**Scope: read_all**

`GET https://app.quickchat.ai/v1/api/knowledge_base/articles/search`

**Query Parameters**

| Parameter | Description |
|-----------|-------------|
| `query` <br/> string, required | Search query |
| `is_case_insensitive` <br/> boolean | Case-insensitive search (default: `true`) |
| `with_title_url_and_tags` <br/> boolean | Include title/URL/tags in search (default: `true`) |
| `strict_search` <br/> boolean | Require exact match (default: `false`) |
| `num_of_display_articles` <br/> integer | Number of articles to display (default: `5`) |
| `num_of_data_articles` <br/> integer | Number of articles to search (default: `15`) |

**Shell**

```shell
curl 'https://app.quickchat.ai/v1/api/knowledge_base/articles/search?query=return%20policy' \
  -H 'Authorization: Bearer <API_TOKEN>'
```

**Python**

```python
import requests

response = requests.get(
    url="https://app.quickchat.ai/v1/api/knowledge_base/articles/search",
    headers={"Authorization": "Bearer <API_TOKEN>"},
    params={"query": "return policy"},
)
data = response.json()
```

**Response** `200 OK`

```json
{
  "article_snippets": [
    {
      "article_id": 1234,
      "expository_sentence": "Our return policy allows returns within 30 days.",
      "query_words_ids": [
        {"start_char": 4, "end_char": 10, "text": "return"}
      ]
    }
  ],
  "article_snapshots": {
    "items": [],
    "offset": 0,
    "count": 1
  }
}
```

## List Paragraphs

List all Paragraph-type articles. Paragraphs are short standalone text entries without a title — as opposed to full Articles which have both a title and content body.

**Scope: read_all**

`GET https://app.quickchat.ai/v1/api/knowledge_base/articles/paragraphs`

**Query Parameters**

| Parameter | Description |
|-----------|-------------|
| `limit` <br/> integer | Items per page |
| `offset` <br/> integer | Items to skip |
| `query` <br/> string | Filter by content |

**Shell**

```shell
curl 'https://app.quickchat.ai/v1/api/knowledge_base/articles/paragraphs?limit=10' \
  -H 'Authorization: Bearer <API_TOKEN>'
```

**Python**

```python
import requests

response = requests.get(
    url="https://app.quickchat.ai/v1/api/knowledge_base/articles/paragraphs",
    headers={"Authorization": "Bearer <API_TOKEN>"},
    params={"limit": 10},
)
data = response.json()
```

**Response** `200 OK`

```json
{
  "items": [
    {
      "id": 1,
      "content": "Our return policy allows returns within 30 days."
    }
  ],
  "offset": 0,
  "count": 1
}
```

---
