# create_comment

Source: https://modulify.ai/docs/api/comments/create-comment

Leaves a new review comment pinned to a spot on the preview of a site.

- Title: Leave a comment on a site
- Scope: `comments:write`
- Access: Makes changes
- Endpoint: `POST /v1/create_comment`

`x`, `y` and `zoom` are required and place the pin. `x` and `y` are fractions of the preview between 0 and 1, and `zoom` is the preview zoom the pin was placed at. Pass `anchor` as well when the comment is about a specific element, so the pin follows that element rather than a fixed spot.

The anchor needs both `Selector` and `PagePath`, and `PagePath` must start with `/`. An anchor missing either, or with any other `PagePath`, is dropped silently and the comment is created unanchored, with the call still reporting success.

The comment is attributed to you. Every workspace member sees it, as does anyone holding the site's shared link while viewers can comment. The text is at most 1,000 characters, and text that is empty or longer than that is refused.

Mentioning a teammate does not email them from here. A mention only sends mail when it is written in the product, so anyone you name sees it when they next open the thread. For the mention to resolve to a person, it takes the composer token form `@Name{userId}` with their real user id from `list_workspace_members`, and a plain `@name` is just text. The tool tells the client to mention someone only when you asked it to. See [Comments](https://modulify.ai/docs/editor/comments#leave-a-comment).

## Request

Call it with a `POST` to `https://api.modulify.ai/v1/create_comment`, sending the inputs below as a JSON object. The token needs the `comments:write` scope.

It makes changes, so send an [Idempotency-Key](https://modulify.ai/docs/api/idempotency) header whenever you might retry it. A retry with the same key gets the first answer back instead of running again.

```bash
curl -X POST https://api.modulify.ai/v1/create_comment \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"projectId":"PROJECT_ID","content":"CONTENT","x":1,"y":1,"zoom":1}'
```

Over MCP, the same method is the [create_comment tool](https://modulify.ai/docs/mcp/comments/create-comment).

## Inputs

| Input | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string | Yes | The site id. |
| `content` | string | Yes | The comment text, at most 1,000 characters. An empty string is refused. |
| `x` | number | Yes | Where the pin sits across the preview, 0 at the left edge and 1 at the right. |
| `y` | number | Yes | Where the pin sits down the preview, 0 at the top and 1 at the bottom. |
| `zoom` | number | Yes | The preview zoom the pin was placed at, normally 1. |
| `anchor` | object | No | Ties the pin to one element so it survives layout changes. Its fields are `PagePath` (the page the element is on, starting with `/`, such as `/pricing`), `Selector` (a CSS selector for the element), `OffsetX` and `OffsetY` (where inside the element the pin sits, 0 to 1), and `DocX` and `DocY` (a fallback position on the page, 0 to 1, used when the element is gone). Leave it out for a comment about the page in general. |

## Response

Every call answers with the [JSON envelope](https://modulify.ai/docs/api/requests-and-responses#the-response) of `success`, `message`, `data`, `code` and `version`. `data` holds the result described above, and on a method that returns a total, `count` carries it. The [response headers](https://modulify.ai/docs/api/requests-and-responses#headers-on-every-method-call) carry the call's `X-Request-Id` and what is left of your per-minute budget in `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. [Errors](https://modulify.ai/docs/api/errors) explains every status code a call can answer with.