curl --request PATCH \
--url https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"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"
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor"
payload = {
"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"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
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'
})
};
fetch('https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor', 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/threads/{thread_id}/anchor",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'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'
]),
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/threads/{thread_id}/anchor"
payload := strings.NewReader("{\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}")
req, _ := http.NewRequest("PATCH", 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.patch("https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\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}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\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}"
response = http.request(request)
puts response.read_body{
"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
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Update comment anchor
Moves a thread’s pin and replaces its screenshot. Only the person who started the thread can do this.
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. The anchor you send replaces the old one in full.
Send screenshot_file_uri to attach a new screenshot, or leave it out or send null to remove the screenshot. 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. 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 PATCH \
--url https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"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"
}
'import requests
url = "https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor"
payload = {
"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"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
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'
})
};
fetch('https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor', 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/threads/{thread_id}/anchor",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'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'
]),
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/threads/{thread_id}/anchor"
payload := strings.NewReader("{\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}")
req, _ := http.NewRequest("PATCH", 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.patch("https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\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}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.base44.com/api/apps/{app_id}/comments/threads/{thread_id}/anchor")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\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}"
response = http.request(request)
puts response.read_body{
"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
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>"
}
]
}Authorizations
Personal access token, sent as Authorization: Bearer <token>.
Body
A thread's new pin and screenshot.
The thread's new pin. It replaces the old one in full.
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"
Response
The thread with its new pin.
A comment thread's state.
ID of the thread.
"68e2b7c1d4f0a9001c3e5a17"
Path of the app page the thread is on.
"/pricing"
Where the thread is pinned in the app's preview.
Show child attributes
Show child attributes
Signed link to the screenshot attached to the thread, valid for one hour. null when the thread has no screenshot or it can't be read.
"https://static.base44.com/images/private/6820f3a4e7b91d003c45a1f2/4b1e9c2a7_shot.png?token=eyJhbGciOi"
When the thread was resolved, in UTC, or null while it's open.
"2026-10-05T09:14:22.512000Z"
Number of replies, not counting the first comment.
2
When the thread was created or last replied to, in UTC.
"2026-10-05T09:14:22.512000Z"
When the thread was created, in UTC.
"2026-10-05T09:14:22.512000Z"
When the builder agent started working on the thread, in UTC, or null when it isn't working on it. A value older than an hour is left over from a turn that stopped.
"2026-10-05T09:14:22.512000Z"
Whether the thread has a comment from someone else posted after you last read it. Always false in the responses of Create comment and Update comment anchor.
true
Was this page helpful?