---
title: "Create a canvas comment thread"
method: POST
path: "/projects/{projectId}/comment-threads"
tags: ["Comments"]
---

# Create a canvas comment thread

`POST /projects/{projectId}/comment-threads`

## Request

- Base URL: `https://app.flora.ai/api/v1`
- URL: `https://app.flora.ai/api/v1/projects/{projectId}/comment-threads`
- Auth: HTTP bearer

Pins a new comment thread on the project canvas at `x`/`y` and posts the first message. Optionally attach the pin to a canvas node with `node_id` (UUID or short id such as n7; unknown short ids are rejected) and `offset_x`/`offset_y`. Generation review threads cannot be created here. Guests who can comment on the project can create threads; they do not need edit or generate permission. Mutating public API requests support an optional Idempotency-Key header for client retries; duplicate keys within two hours return idempotency_duplicate.

## Path parameters

- `projectId` string, required: Project identifier

## Request body

- object
  - `body` string, required: Plain-text comment body
  - `x` number, required: Canvas X coordinate of the pin
  - `y` number, required: Canvas Y coordinate of the pin
  - `node_id` string: Attach the pin to this canvas node
  - `offset_x` number: Horizontal offset from the node's origin when node_id is set. Defaults to 0.
  - `offset_y` number: Vertical offset from the node's origin when node_id is set. Defaults to 0.
  - `author` 'user': Who the comment is attributed to. `user` posts as the credential's user. Defaults to `user`.

## Response `201`

Comment thread created.

- object
  - `comment_thread_id` string, required: Comment thread identifier
  - `project_id` string, required: Project identifier
  - `workspace_id` string, required: Workspace identifier
  - `status` 'open' | 'resolved', required: Whether the thread is still open
  - `resolved_at` number, nullable, required: When the thread was resolved, as a Unix timestamp in milliseconds. Null while open.
  - `created_at` number, required: When the thread was created, as a Unix timestamp in milliseconds
  - `last_comment_at` number, nullable, required: When the latest live comment was created, as a Unix timestamp in milliseconds. Null when the thread has no live comments.
  - `comment_count` integer, required: Number of live comments in the thread
  - `anchor` 'canvas' | 'generation', required: Where the thread is pinned. `canvas` is a pin on the project canvas. `generation` is a review thread on a generation.
  - `generation_id` string: Public run id of the generation this review thread is pinned to. Absent on canvas threads.
  - `position` object, required
    - `x` number, required: Canvas X coordinate of the pin
    - `y` number, required: Canvas Y coordinate of the pin
    - `node_id` string: Canvas node the pin is attached to, when pinned to a node
  - `preview` object, nullable, required: The first live comment in the thread. Null when the thread has no live comments.
    - `comment_id` string, required: Comment identifier
    - `body` string, required: Plain-text comment body
    - `author` object, required
      - `type` 'user' | 'anonymous' | 'flora', required: Author kind
      - `name` string, required: Display name
      - `profile_image_url` string, uri: Author profile image URL
    - `created_at` number, required: When the comment was created, as a Unix timestamp in milliseconds
  - `messages` object[], required: Live comments in the thread, oldest first
    - `comment_id` string, required: Comment identifier
    - `body` string, required: Plain-text comment body
    - `author` object, required
      - `type` 'user' | 'anonymous' | 'flora', required: Author kind
      - `name` string, required: Display name
      - `profile_image_url` string, uri: Author profile image URL
    - `created_at` number, required: When the comment was created, as a Unix timestamp in milliseconds

## Other responses

- `400`: 400
- `401`: 401
- `402`: 402
- `403`: 403
- `404`: 404
- `409`: 409
- `429`: 429
- `500`: 500
- `503`: 503

## Changes

- **2026-10-28** `a8351619f225`: 9 warning
  - added the new `not_configured` enum value to the `error/code` response property for the response status `400`
  - added the new `not_configured` enum value to the `error/code` response property for the response status `401`
  - added the new `not_configured` enum value to the `error/code` response property for the response status `402`
  - added the new `not_configured` enum value to the `error/code` response property for the response status `403`
  - …5 more
- **2026-10-16** `e54130373b10`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/florafauna-ai/apis/flora-ai-api/changes/projects/:projectId/comment-threads/post.md)

---

[API](https://skmtc.dev/florafauna-ai/apis/flora-ai-api.md) - [All operations](https://skmtc.dev/florafauna-ai/apis/flora-ai-api/llms.txt) - [OpenAPI document](https://skmtc.dev/florafauna-ai/apis/flora-ai-api/revisions/87cfe2c4ac29?raw)
