# Comments

_Category: REST API reference_

Read what readers ask under your articles, work the moderation queue, and answer as your team. The comments endpoints list every comment on your help center or one article's conversation, approve and reject comments, post replies, and delete comments.

Comments are available on every plan. The private notes your team leaves on articles are a separate resource that these endpoints never return: see [Team notes](https://developers.helpcenter.io/content/team-notes-api). Reader votes on an article (helpful or not) are recorded with the [Articles](https://developers.helpcenter.io/content/articles-api) endpoints.

## Endpoints

| Method and path | What it does | Access |
| --- | --- | --- |
| `GET /v1/comments` | List the comments on your help center. | Any API key. OAuth: `content.read` |
| `GET /v1/articles/{articleId}/comments` | Get one article's comments as threads. | Any API key. OAuth: `content.read` |
| `POST /v1/articles/{articleId}/comments` | Post a comment or a reply. | Read & write key. OAuth: `content.write` |
| `PATCH /v1/comments/{commentId}` | Approve or reject a comment. | Read & write key. OAuth: `content.write` |
| `DELETE /v1/comments/{commentId}` | Delete a comment. | Read & write key. OAuth: `content.write` |

An API key works with the help center it was created in. An OAuth app names the help center with the `X-HCio-Site` header (see [Choose which help center a request acts on](https://developers.helpcenter.io/content/choosing-a-help-center)). A Read only key on a write endpoint gets `403 Forbidden` with the code `insufficient_scope`. Reads count toward the limit of 300 requests a minute per API key or OAuth app, and writes also toward 120 a minute (see [Rate limits](https://developers.helpcenter.io/content/rate-limits)).

## The comment object

| Field | Type | Description |
| --- | --- | --- |
| `id` | integer | The comment's ID. |
| `article_id` | integer | The article the comment is on. |
| `parent_id` | integer or null | The comment this one replies to. `null` for a top-level comment. |
| `lang` | string | The language the comment was written in, for example `en`. Readers see a comment only on the article in that language. |
| `status` | string | `pending` (waiting for approval), `published` or `unpublished` (rejected). A deleted comment keeps the status it had. |
| `deleted` | boolean | `true` for a deleted comment. You get deleted comments only when you ask for `status=deleted`. |
| `comment` | string | The text, as plain text: HTML tags are removed and entities such as `&amp;` are decoded. |
| `author` | object | Who wrote it. `name`; `type`, `user` for someone who was signed in (a team member, or a reader signed in to your help center) or `visitor` for someone who typed a name; `user_id`, `null` for visitors; and `email`, only when you ask for it (see Reader email addresses below). IP addresses are never returned. |
| `rating` | integer | Up-votes readers gave the comment on your help center. |
| `created_at`, `updated_at` | string | ISO 8601 in UTC, for example `2026-09-30T08:15:09+00:00`. |
| `article` | object | `id` and `title` of the article. Present in `GET /v1/comments` and in the responses of `POST` and `PATCH`. `title` is a string in the comment's language when the article has one, otherwise in another language the article has. |
| `replies` | array | Only in an article's threads: the replies, each a comment object with its own `replies`. |
| `_links` | object | `moderate`, `delete` and `reply`, each with the `method` and `url` to call. |

## List comments

GET`/v1/comments`

List the comments on your help center, newest first. Filter by status, article, language or text.

Use it as the moderation queue (`status=pending`) or as the feed of what readers ask. All parameters are optional:

| Parameter | Type | Description |
| --- | --- | --- |
| `status` | string | Default `all`: every comment that is not deleted. `pending`, `published` and `unpublished` filter by status; `deleted` returns only deleted comments. |
| `article_id` | integer | Only the comments on this article. An article of another help center, or one in the Trash, gets `404 Not Found`. |
| `lang` | string | Only comments in this language. It must be a language of your help center. |
| `search` | string | Only comments whose text contains this, up to 190 characters. A search that contains `'`, `"`, `&`, `<` or `>` can miss comments written by readers, and `%` matches any text and `_` any single character. |
| `order` | string | `desc` (default, newest first) or `asc`, by `created_at`. |
| `page`, `limit` | integer | The page, from 1, and comments per page, 1 to 100. Default `limit`: 25. |
| `include_email` | 1 or 0 | Add each author's email address. Default `0`. |

`meta` gives `page`, `per_page`, `total_pages` (at least 1) and `items_count`, the number of comments that match your filters. `meta.status_counts` counts the whole help center's comments by status, whatever your filters, so one call tells you how many are waiting.

Comments on articles in the Trash are left out of every comments endpoint and of the counts, and moderating or deleting one answers `404`.

### Reader email addresses

Comments come without email addresses. Add `include_email=1` when you need to contact the people who wrote them:

```
curl "https://api.helpcenter.io/v1/comments?status=published&include_email=1" \
  -H "apikey: $HELPCENTER_API_KEY" \
  -H "Accept: application/json"
```

Each `author` then carries `email`: the address a visitor typed, or the account's address for someone who was signed in.

```
"author": {
  "name": "Jane Doe",
  "type": "visitor",
  "user_id": null,
  "email": "jane.doe@example.com"
}
```

- The value must be `1` or `0`. `include_email=true` is refused with `422 Unprocessable Entity` and "The include email field must be true or false."
- Email addresses need write access: a **Read & write** API key, or an OAuth token with `content.write`. A Read only key gets `403 Forbidden`.
- Addresses are personal data: request them only when you are going to use them. IP addresses are never returned.

## Get an article's comments

GET`/v1/articles/{articleId}/comments`

Get one article's comments as threads, oldest first, with replies nested under the comment they answer.

The top-level comments come oldest first, each with its `replies` nested to any depth. `meta.threads_count` is the number of top-level comments and `meta.comments_count` the number of comments in the response, replies included. The top-level `article.title` is an object with every language of the title.

| Parameter | Type | Description |
| --- | --- | --- |
| `status` | string | As for the list. It applies at every level: a reply that does not match is left out, with its own replies. |
| `lang` | string | As for the list, and at every level. |
| `order` | string | `asc` (default) or `desc`, for the top-level comments. |
| `include_email` | 1 or 0 | As for the list, with the same key rules. |

There is no paging: you get the whole conversation. `search`, `article_id`, `page` and `limit` are accepted and have no effect.

When a comment that has replies is deleted, this view leaves out the comment and its replies. The replies still appear in `GET /v1/comments`, with `parent_id` pointing at the deleted comment.

## Post a comment or a reply

POST`/v1/articles/{articleId}/comments`

Post a comment on an article, or a reply to one, as the person the API key or token belongs to. It is published at once.

| Field | Type | Description |
| --- | --- | --- |
| `comment` | string | Required. Plain text, 1 to 5000 characters. HTML is shown as text, not as formatting. |
| `parent_id` | integer | The comment you are replying to. It must be a comment on the same article that is not deleted; any status works, pending included. |
| `lang` | string | A language of your help center. Default: the language of the comment you reply to, or your help center's default language for a top-level comment. |

- **The author is the credential's owner.** A comment posted with an API key is signed by the team member who created the key; with an OAuth token, by the person who approved the app. There is no field to post under another name.
- **It is published at once**, whatever your help center's approval setting. Readers see it on the article in its language, wherever your help center shows comments.
- **Reply to the top-level comment.** Your help center shows one level of replies under each comment. A reply to a reply is saved and returned by the API, but readers may not see it.
- **It sends email.** A reply emails the author of the comment you replied to ("Your comment got a reply"), unless they unsubscribed, their address isn't a valid email address, or it is their own address, and even when their comment is still pending. A top-level comment emails the article's author ("A new comment has been posted").
- **It is not idempotent.** Sending the same request twice posts two comments. If a request times out, read the article's comments before you try again.

## Approve or reject a comment

PATCH`/v1/comments/{commentId}`

Approve (published) or reject (unpublished) a comment. The comment's text cannot be changed.

Send `published` to approve a comment or `unpublished` to reject it. You can change your mind later: both work on any comment that is not deleted, and setting the status it already has answers `200`. The text of a comment can't be changed through the API.

Approving a reply that wasn't published yet emails the author of the comment it answers ("Your comment got a reply"), once per reply. Approving a top-level comment sends no email.

## Delete a comment

DELETE`/v1/comments/{commentId}`

Delete a comment. It can be restored from the dashboard, and its replies stay.

A deleted comment is taken off the help center, and its replies stay. When it has replies, readers see a note that the comment was deleted in its place. Deleting the same comment again answers `200` with "Comment was already deleted.", so a retry is safe.

Restoring a comment, and deleting it for good, happen in the dashboard (see [Approve and answer reader comments](https://self.helpcenter.io/content/moderate-comments)). To take a comment off the help center in a way you can undo over the API, reject it instead.

## Errors

| Status | When |
| --- | --- |
| `401 Unauthorized` | The key or token is missing or not valid: `{"status": "unauthorized"}`. |
| `403 Forbidden` | `insufficient_scope`: a Read only key, or an OAuth token without the scope, on a write endpoint. Also a Read only key with `include_email=1`. |
| `404 Not Found` | "Article not found.", "Comment not found.", "No such comment on this article to reply to." or "This comment was deleted. Restore it from the dashboard before moderating it." |
| `422 Unprocessable Entity` | A parameter or field is not valid. `errors` names it, for example "Unknown status. Use pending, published, unpublished, deleted or all." or "That language is not enabled on this help center." |
| `429 Too Many Requests` | Over the rate limit. Wait for the seconds in `Retry-After`. |

For the error format and the errors every endpoint shares, see [Errors](https://developers.helpcenter.io/content/errors).

## Related

- [Team notes](https://developers.helpcenter.io/content/team-notes-api)
- [Articles](https://developers.helpcenter.io/content/articles-api)
- [Webhooks](https://developers.helpcenter.io/content/webhooks)
