curl --request POST \
--url https://app.base44.com/api/apps/{app_id}/comments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"content": "Make this button match the header color.",
"page_path": "/pricing",
"anchor": {
"source_location": "pages/Pricing.jsx:42:8",
"element_tag": "button",
"instance_index": 0,
"point": {
"x": 0.5,
"y": 0.5
},
"crop": {
"x": 512,
"y": 1340,
"width": 240,
"height": 96
},
"region": {
"x": 0.42,
"y": 0.18,
"width": 0.2,
"height": 0.08
},
"viewport_size": {
"width": 1280,
"height": 800
}
},
"screenshot_file_uri": "mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png",
"mentioned_emails": [
"dana@acme.com"
]
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/comments"
payload = {
"content": "Make this button match the header color.",
"page_path": "/pricing",
"anchor": {
"source_location": "pages/Pricing.jsx:42:8",
"element_tag": "button",
"instance_index": 0,
"point": {
"x": 0.5,
"y": 0.5
},
"crop": {
"x": 512,
"y": 1340,
"width": 240,
"height": 96
},
"region": {
"x": 0.42,
"y": 0.18,
"width": 0.2,
"height": 0.08
},
"viewport_size": {
"width": 1280,
"height": 800
}
},
"screenshot_file_uri": "mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png",
"mentioned_emails": ["dana@acme.com"]
}
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({
content: 'Make this button match the header color.',
page_path: '/pricing',
anchor: {
source_location: 'pages/Pricing.jsx:42:8',
element_tag: 'button',
instance_index: 0,
point: {x: 0.5, y: 0.5},
crop: {x: 512, y: 1340, width: 240, height: 96},
region: {x: 0.42, y: 0.18, width: 0.2, height: 0.08},
viewport_size: {width: 1280, height: 800}
},
screenshot_file_uri: 'mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png',
mentioned_emails: ['dana@acme.com']
})
};
fetch('https://app.base44.com/api/apps/{app_id}/comments', 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://app.base44.com/api/apps/{app_id}/comments",
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([
'content' => 'Make this button match the header color.',
'page_path' => '/pricing',
'anchor' => [
'source_location' => 'pages/Pricing.jsx:42:8',
'element_tag' => 'button',
'instance_index' => 0,
'point' => [
'x' => 0.5,
'y' => 0.5
],
'crop' => [
'x' => 512,
'y' => 1340,
'width' => 240,
'height' => 96
],
'region' => [
'x' => 0.42,
'y' => 0.18,
'width' => 0.2,
'height' => 0.08
],
'viewport_size' => [
'width' => 1280,
'height' => 800
]
],
'screenshot_file_uri' => 'mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png',
'mentioned_emails' => [
'dana@acme.com'
]
]),
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://app.base44.com/api/apps/{app_id}/comments"
payload := strings.NewReader("{\n \"content\": \"Make this button match the header color.\",\n \"page_path\": \"/pricing\",\n \"anchor\": {\n \"source_location\": \"pages/Pricing.jsx:42:8\",\n \"element_tag\": \"button\",\n \"instance_index\": 0,\n \"point\": {\n \"x\": 0.5,\n \"y\": 0.5\n },\n \"crop\": {\n \"x\": 512,\n \"y\": 1340,\n \"width\": 240,\n \"height\": 96\n },\n \"region\": {\n \"x\": 0.42,\n \"y\": 0.18,\n \"width\": 0.2,\n \"height\": 0.08\n },\n \"viewport_size\": {\n \"width\": 1280,\n \"height\": 800\n }\n },\n \"screenshot_file_uri\": \"mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png\",\n \"mentioned_emails\": [\n \"dana@acme.com\"\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://app.base44.com/api/apps/{app_id}/comments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"content\": \"Make this button match the header color.\",\n \"page_path\": \"/pricing\",\n \"anchor\": {\n \"source_location\": \"pages/Pricing.jsx:42:8\",\n \"element_tag\": \"button\",\n \"instance_index\": 0,\n \"point\": {\n \"x\": 0.5,\n \"y\": 0.5\n },\n \"crop\": {\n \"x\": 512,\n \"y\": 1340,\n \"width\": 240,\n \"height\": 96\n },\n \"region\": {\n \"x\": 0.42,\n \"y\": 0.18,\n \"width\": 0.2,\n \"height\": 0.08\n },\n \"viewport_size\": {\n \"width\": 1280,\n \"height\": 800\n }\n },\n \"screenshot_file_uri\": \"mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png\",\n \"mentioned_emails\": [\n \"dana@acme.com\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/comments")
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 \"content\": \"Make this button match the header color.\",\n \"page_path\": \"/pricing\",\n \"anchor\": {\n \"source_location\": \"pages/Pricing.jsx:42:8\",\n \"element_tag\": \"button\",\n \"instance_index\": 0,\n \"point\": {\n \"x\": 0.5,\n \"y\": 0.5\n },\n \"crop\": {\n \"x\": 512,\n \"y\": 1340,\n \"width\": 240,\n \"height\": 96\n },\n \"region\": {\n \"x\": 0.42,\n \"y\": 0.18,\n \"width\": 0.2,\n \"height\": 0.08\n },\n \"viewport_size\": {\n \"width\": 1280,\n \"height\": 800\n }\n },\n \"screenshot_file_uri\": \"mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png\",\n \"mentioned_emails\": [\n \"dana@acme.com\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"thread": {
"id": "68e2b7c1d4f0a9001c3e5a17",
"page_path": "/pricing",
"anchor": {
"source_location": "pages/Pricing.jsx:42:8",
"element_tag": "button",
"instance_index": 0,
"point": {
"x": 0.5,
"y": 0.5
},
"crop": {
"x": 512,
"y": 1340,
"width": 240,
"height": 96
},
"region": {
"x": 0.42,
"y": 0.18,
"width": 0.2,
"height": 0.08
},
"viewport_size": {
"width": 1280,
"height": 800
}
},
"screenshot_url": "https://static.base44.com/images/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png?token=eyJhbGciOi",
"resolved_at": "2026-10-05T09:14:22.512000Z",
"message_count": 2,
"last_activity_at": "2026-10-05T09:14:22.512000Z",
"created_date": "2026-10-05T09:14:22.512000Z",
"agent_working_since": "2026-10-05T09:14:22.512000Z",
"unread": true
},
"comment": {
"id": "68e2b7c4d4f0a9001c3e5a1c",
"content": "Make this button match the header color.",
"sender_id": "6820f41be7b91d003c45a20a",
"sender_name": "Dana Levi",
"sender_avatar_url": "https://lh3.googleusercontent.com/a/ACg8ocJ2",
"created_date": "2026-10-05T09:14:22.512000Z",
"edited_at": "2026-10-05T09:14:22.512000Z",
"reactions": {
"👍": [
"6820f41be7b91d003c45a20a"
]
}
},
"replies": [
{
"content": "Done, it now uses the header blue.",
"created_date": "2026-10-05T09:14:22.512000Z",
"id": "68e2b80fd4f0a9001c3e5a21",
"reactions": {},
"sender_id": "base44",
"sender_name": "Base44"
}
],
"reactor_names": {
"6820f41be7b91d003c45a20a": "Dana Levi"
}
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Create comment
Starts a new comment thread on the app with its first comment.
Set page_path to the app page the comment is about. anchor pins the thread to an element of the app’s preview. The builder fills it in when you click an element, and source_location must match that element’s data-source-location attribute in the preview for a pin to show. Leave anchor out to post a thread with no pin. It still shows in the builder’s comments panel.
To attach a screenshot, upload the image with Upload app file and visibility set to private, then pass its file_uri as screenshot_file_uri. Only private files uploaded to this app are accepted.
mentioned_emails records who the comment mentions. Only emails that List mentionable users returns are kept, and the rest are dropped without an error. Mentioning someone sends them no email or notification, and responses never return the list.
Comments don’t reach the builder agent on their own. It only works on a thread when someone sends the thread to the builder chat from the builder. Anyone with the app open in the builder sees the change right away.
This is limited to 120 requests per minute per app, shared by every other comments endpoint. A signed-in session has its own limit, and every personal access token for the workspace shares one. Some workspaces have a different limit. Every request that counts against the limit gets X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix time in seconds) headers, and a 429 also gets Retry-After in seconds. If the limiter itself is unavailable, requests go through without these headers.
curl --request POST \
--url https://app.base44.com/api/apps/{app_id}/comments \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"content": "Make this button match the header color.",
"page_path": "/pricing",
"anchor": {
"source_location": "pages/Pricing.jsx:42:8",
"element_tag": "button",
"instance_index": 0,
"point": {
"x": 0.5,
"y": 0.5
},
"crop": {
"x": 512,
"y": 1340,
"width": 240,
"height": 96
},
"region": {
"x": 0.42,
"y": 0.18,
"width": 0.2,
"height": 0.08
},
"viewport_size": {
"width": 1280,
"height": 800
}
},
"screenshot_file_uri": "mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png",
"mentioned_emails": [
"dana@acme.com"
]
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/comments"
payload = {
"content": "Make this button match the header color.",
"page_path": "/pricing",
"anchor": {
"source_location": "pages/Pricing.jsx:42:8",
"element_tag": "button",
"instance_index": 0,
"point": {
"x": 0.5,
"y": 0.5
},
"crop": {
"x": 512,
"y": 1340,
"width": 240,
"height": 96
},
"region": {
"x": 0.42,
"y": 0.18,
"width": 0.2,
"height": 0.08
},
"viewport_size": {
"width": 1280,
"height": 800
}
},
"screenshot_file_uri": "mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png",
"mentioned_emails": ["dana@acme.com"]
}
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({
content: 'Make this button match the header color.',
page_path: '/pricing',
anchor: {
source_location: 'pages/Pricing.jsx:42:8',
element_tag: 'button',
instance_index: 0,
point: {x: 0.5, y: 0.5},
crop: {x: 512, y: 1340, width: 240, height: 96},
region: {x: 0.42, y: 0.18, width: 0.2, height: 0.08},
viewport_size: {width: 1280, height: 800}
},
screenshot_file_uri: 'mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png',
mentioned_emails: ['dana@acme.com']
})
};
fetch('https://app.base44.com/api/apps/{app_id}/comments', 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://app.base44.com/api/apps/{app_id}/comments",
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([
'content' => 'Make this button match the header color.',
'page_path' => '/pricing',
'anchor' => [
'source_location' => 'pages/Pricing.jsx:42:8',
'element_tag' => 'button',
'instance_index' => 0,
'point' => [
'x' => 0.5,
'y' => 0.5
],
'crop' => [
'x' => 512,
'y' => 1340,
'width' => 240,
'height' => 96
],
'region' => [
'x' => 0.42,
'y' => 0.18,
'width' => 0.2,
'height' => 0.08
],
'viewport_size' => [
'width' => 1280,
'height' => 800
]
],
'screenshot_file_uri' => 'mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png',
'mentioned_emails' => [
'dana@acme.com'
]
]),
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://app.base44.com/api/apps/{app_id}/comments"
payload := strings.NewReader("{\n \"content\": \"Make this button match the header color.\",\n \"page_path\": \"/pricing\",\n \"anchor\": {\n \"source_location\": \"pages/Pricing.jsx:42:8\",\n \"element_tag\": \"button\",\n \"instance_index\": 0,\n \"point\": {\n \"x\": 0.5,\n \"y\": 0.5\n },\n \"crop\": {\n \"x\": 512,\n \"y\": 1340,\n \"width\": 240,\n \"height\": 96\n },\n \"region\": {\n \"x\": 0.42,\n \"y\": 0.18,\n \"width\": 0.2,\n \"height\": 0.08\n },\n \"viewport_size\": {\n \"width\": 1280,\n \"height\": 800\n }\n },\n \"screenshot_file_uri\": \"mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png\",\n \"mentioned_emails\": [\n \"dana@acme.com\"\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://app.base44.com/api/apps/{app_id}/comments")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"content\": \"Make this button match the header color.\",\n \"page_path\": \"/pricing\",\n \"anchor\": {\n \"source_location\": \"pages/Pricing.jsx:42:8\",\n \"element_tag\": \"button\",\n \"instance_index\": 0,\n \"point\": {\n \"x\": 0.5,\n \"y\": 0.5\n },\n \"crop\": {\n \"x\": 512,\n \"y\": 1340,\n \"width\": 240,\n \"height\": 96\n },\n \"region\": {\n \"x\": 0.42,\n \"y\": 0.18,\n \"width\": 0.2,\n \"height\": 0.08\n },\n \"viewport_size\": {\n \"width\": 1280,\n \"height\": 800\n }\n },\n \"screenshot_file_uri\": \"mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png\",\n \"mentioned_emails\": [\n \"dana@acme.com\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/comments")
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 \"content\": \"Make this button match the header color.\",\n \"page_path\": \"/pricing\",\n \"anchor\": {\n \"source_location\": \"pages/Pricing.jsx:42:8\",\n \"element_tag\": \"button\",\n \"instance_index\": 0,\n \"point\": {\n \"x\": 0.5,\n \"y\": 0.5\n },\n \"crop\": {\n \"x\": 512,\n \"y\": 1340,\n \"width\": 240,\n \"height\": 96\n },\n \"region\": {\n \"x\": 0.42,\n \"y\": 0.18,\n \"width\": 0.2,\n \"height\": 0.08\n },\n \"viewport_size\": {\n \"width\": 1280,\n \"height\": 800\n }\n },\n \"screenshot_file_uri\": \"mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png\",\n \"mentioned_emails\": [\n \"dana@acme.com\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"thread": {
"id": "68e2b7c1d4f0a9001c3e5a17",
"page_path": "/pricing",
"anchor": {
"source_location": "pages/Pricing.jsx:42:8",
"element_tag": "button",
"instance_index": 0,
"point": {
"x": 0.5,
"y": 0.5
},
"crop": {
"x": 512,
"y": 1340,
"width": 240,
"height": 96
},
"region": {
"x": 0.42,
"y": 0.18,
"width": 0.2,
"height": 0.08
},
"viewport_size": {
"width": 1280,
"height": 800
}
},
"screenshot_url": "https://static.base44.com/images/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png?token=eyJhbGciOi",
"resolved_at": "2026-10-05T09:14:22.512000Z",
"message_count": 2,
"last_activity_at": "2026-10-05T09:14:22.512000Z",
"created_date": "2026-10-05T09:14:22.512000Z",
"agent_working_since": "2026-10-05T09:14:22.512000Z",
"unread": true
},
"comment": {
"id": "68e2b7c4d4f0a9001c3e5a1c",
"content": "Make this button match the header color.",
"sender_id": "6820f41be7b91d003c45a20a",
"sender_name": "Dana Levi",
"sender_avatar_url": "https://lh3.googleusercontent.com/a/ACg8ocJ2",
"created_date": "2026-10-05T09:14:22.512000Z",
"edited_at": "2026-10-05T09:14:22.512000Z",
"reactions": {
"👍": [
"6820f41be7b91d003c45a20a"
]
}
},
"replies": [
{
"content": "Done, it now uses the header blue.",
"created_date": "2026-10-05T09:14:22.512000Z",
"id": "68e2b80fd4f0a9001c3e5a21",
"reactions": {},
"sender_id": "base44",
"sender_name": "Base44"
}
],
"reactor_names": {
"6820f41be7b91d003c45a20a": "Dana Levi"
}
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Authorizations
Personal access token, sent as Authorization: Bearer <token>.
Path Parameters
ID of the app.
Body
A new comment thread.
Text of the comment, 1 to 5000 characters.
1 - 5000"Make this button match the header color."
Path of the app page the comment is about. Defaults to /.
512"/pricing"
Where to pin the thread in the app's preview. Leave it out for a thread with no pin.
Show child attributes
Show child attributes
file_uri of a screenshot uploaded to this app with Upload app file and visibility set to private. Starts with mp/private/ followed by the app's ID.
2000"mp/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png"
Emails of up to 50 people the comment mentions. Mentions send no notification.
50["dana@acme.com"]
Response
The new thread with its first comment.
A comment thread with all its comments.
The thread's state.
Show child attributes
Show child attributes
The first comment, which started the thread.
Show child attributes
Show child attributes
Replies, oldest first.
Show child attributes
Show child attributes
[ { "content": "Done, it now uses the header blue.", "created_date": "2026-10-05T09:14:22.512000Z", "id": "68e2b80fd4f0a9001c3e5a21", "reactions": {}, "sender_id": "base44", "sender_name": "Base44" } ]
User ID mapped to name, for the people who reacted anywhere in the thread.
Show child attributes
Show child attributes
{ "6820f41be7b91d003c45a20a": "Dana Levi" }
Was this page helpful?