Reply to a preview comment
Appends a reply. Authorship comes from the authenticated principal.
Idempotent on the reply’s client_id: repeating a request appends
nothing and succeeds.
Set author_kind to agent to record the agent’s answer instead of a
person’s. A reply bound to the active run moves it from handed to
review, and leaves every other status where a person put it: the agent
can answer a thread but never close it, and never reopens one somebody
decided. Reopening or skipping a thread revokes its run; later replies
carrying that identity receive 409. While the run remains authorized,
repeating its answer stores nothing and succeeds, so the same body
cannot arrive twice under two ids.
Replying is discussion and is never refused for belonging to work. When the thread belongs to a work item, though, the run that owns the thread is the work item’s and not the comment’s: an answer carrying any other identity receives 409, and an answer that does land leaves the thread where it is, because a linked thread’s status belongs to the work item.
curl --request POST \
--url https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"reply": {
"client_id": "r-5c20e9b4",
"body": "Agreed. Let's drop the font size a step below 768px rather than rewording it.",
"mentions": []
}
}
EOFimport requests
url = "https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies"
payload = { "reply": {
"client_id": "r-5c20e9b4",
"body": "Agreed. Let's drop the font size a step below 768px rather than rewording it.",
"mentions": []
} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
reply: {
client_id: 'r-5c20e9b4',
body: JSON.stringify('Agreed. Let\'s drop the font size a step below 768px rather than rewording it.'),
mentions: []
}
})
};
fetch('https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reply' => [
'client_id' => 'r-5c20e9b4',
'body' => 'Agreed. Let\'s drop the font size a step below 768px rather than rewording it.',
'mentions' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies"
payload := strings.NewReader("{\n \"reply\": {\n \"client_id\": \"r-5c20e9b4\",\n \"body\": \"Agreed. Let's drop the font size a step below 768px rather than rewording it.\",\n \"mentions\": []\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reply\": {\n \"client_id\": \"r-5c20e9b4\",\n \"body\": \"Agreed. Let's drop the font size a step below 768px rather than rewording it.\",\n \"mentions\": []\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reply\": {\n \"client_id\": \"r-5c20e9b4\",\n \"body\": \"Agreed. Let's drop the font size a step below 768px rather than rewording it.\",\n \"mentions\": []\n }\n}"
response = http.request(request)
puts response.read_body{
"preview_comment": {
"id": 31877,
"run_id": null,
"lock_version": 3,
"client_id": "c-3f9a2e71",
"n": 4,
"body": "The hero headline wraps onto three lines on mobile. Can we tighten it so it fits on two?",
"status": "open",
"status_at_ms": 1789398131000,
"page_url": "/",
"author_name": "Michael Scott",
"created_at_ms": 1789398131000,
"template_id": 902114,
"section": {
"id": "hero-banner-1",
"type": "hero-banner"
},
"block": null,
"target": {
"tag": "h1",
"selector": "section[data-section-id=\"hero-banner-1\"] h1.hero__title",
"text": "Limitless Paper in a Paperless World",
"html": "<h1 class=\"hero__title\">Limitless Paper in a Paperless World</h1>"
},
"pin": {
"x": 48.2,
"y": 22.7,
"ox": 0.41,
"oy": 0.63
},
"mentions": [
{
"id": "52018",
"name": "Pam Beesly"
}
],
"mentioned_project": null,
"proof_baseline": null,
"work_item": null,
"board_position": null,
"board_position_at_ms": null,
"assignee": null,
"assigner": null,
"assigned_at_ms": null,
"priority": null,
"priority_at_ms": null,
"replies": [
{
"client_id": "r-5c20e9b4",
"run_id": null,
"body": "Agreed. Let's drop the font size a step below 768px rather than rewording it.",
"author_name": "Pam Beesly",
"created_at_ms": 1789398277000,
"mentions": [],
"shot": null,
"proof": null
}
]
},
"status": 201,
"meta": {
"request_uuid": "7c1e9a52-4b3d-4f0e-9d2a-81f6c3b5e240",
"timestamp": "2026-09-14T15:04:37Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Id of the theme the comment belongs to.
Client-generated id of the comment being replied to.
Body
Show child attributes
Show child attributes
Response
The comment, with the reply appended.
A single comment, wrapped in the standard response envelope.
curl --request POST \
--url https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data @- <<EOF
{
"reply": {
"client_id": "r-5c20e9b4",
"body": "Agreed. Let's drop the font size a step below 768px rather than rewording it.",
"mentions": []
}
}
EOFimport requests
url = "https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies"
payload = { "reply": {
"client_id": "r-5c20e9b4",
"body": "Agreed. Let's drop the font size a step below 768px rather than rewording it.",
"mentions": []
} }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
reply: {
client_id: 'r-5c20e9b4',
body: JSON.stringify('Agreed. Let\'s drop the font size a step below 768px rather than rewording it.'),
mentions: []
}
})
};
fetch('https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'reply' => [
'client_id' => 'r-5c20e9b4',
'body' => 'Agreed. Let\'s drop the font size a step below 768px rather than rewording it.',
'mentions' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies"
payload := strings.NewReader("{\n \"reply\": {\n \"client_id\": \"r-5c20e9b4\",\n \"body\": \"Agreed. Let's drop the font size a step below 768px rather than rewording it.\",\n \"mentions\": []\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"reply\": {\n \"client_id\": \"r-5c20e9b4\",\n \"body\": \"Agreed. Let's drop the font size a step below 768px rather than rewording it.\",\n \"mentions\": []\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.fluid.app/api/v202604/themes/{theme_id}/preview_comments/{client_id}/replies")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"reply\": {\n \"client_id\": \"r-5c20e9b4\",\n \"body\": \"Agreed. Let's drop the font size a step below 768px rather than rewording it.\",\n \"mentions\": []\n }\n}"
response = http.request(request)
puts response.read_body{
"preview_comment": {
"id": 31877,
"run_id": null,
"lock_version": 3,
"client_id": "c-3f9a2e71",
"n": 4,
"body": "The hero headline wraps onto three lines on mobile. Can we tighten it so it fits on two?",
"status": "open",
"status_at_ms": 1789398131000,
"page_url": "/",
"author_name": "Michael Scott",
"created_at_ms": 1789398131000,
"template_id": 902114,
"section": {
"id": "hero-banner-1",
"type": "hero-banner"
},
"block": null,
"target": {
"tag": "h1",
"selector": "section[data-section-id=\"hero-banner-1\"] h1.hero__title",
"text": "Limitless Paper in a Paperless World",
"html": "<h1 class=\"hero__title\">Limitless Paper in a Paperless World</h1>"
},
"pin": {
"x": 48.2,
"y": 22.7,
"ox": 0.41,
"oy": 0.63
},
"mentions": [
{
"id": "52018",
"name": "Pam Beesly"
}
],
"mentioned_project": null,
"proof_baseline": null,
"work_item": null,
"board_position": null,
"board_position_at_ms": null,
"assignee": null,
"assigner": null,
"assigned_at_ms": null,
"priority": null,
"priority_at_ms": null,
"replies": [
{
"client_id": "r-5c20e9b4",
"run_id": null,
"body": "Agreed. Let's drop the font size a step below 768px rather than rewording it.",
"author_name": "Pam Beesly",
"created_at_ms": 1789398277000,
"mentions": [],
"shot": null,
"proof": null
}
]
},
"status": 201,
"meta": {
"request_uuid": "7c1e9a52-4b3d-4f0e-9d2a-81f6c3b5e240",
"timestamp": "2026-09-14T15:04:37Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}{
"error": {
"message": "<string>",
"details": {}
},
"status": 123,
"meta": {
"request_uuid": "<string>",
"timestamp": "2023-11-07T05:31:56Z"
}
}